"Dynamische" Factory
-
Hi,
Ich bin momentan dabei eine Anwendung zu schreiben, die sich anhand eines Strings ein (Command-)Objekt über eine Faktory holen soll.
(Also Quasi: Factory.GetInstance().GetCommand(string sBefehl))Momentan habe ich in GetCommand einen Switch drin, in den ich jeden Befehl eintrage, und dann entsprechend eine Abgeleitete Klasse von Command erstelle und zurückgebe.
Jetzt wollte ich das ganze mit einer Map machen. Also in den Konstructor der Faktory kommt sowas wie: Map.Add("Befehl", AbgeleiteteKlasseVonCommand).
In GetCommand wird dann in der Map der Befehl gesucht, und ein Objekt von der entsprechenden Klasse erstellt und zurückgegeben.Ich hoffe das war verständlich.
Kann mir da vielleicht jemand weiterhelfen, oder hat nen Link parat (Mit würds denk ich mal schon helfen, wenn ich wenigstens wüsste wonach ich bei Google suchen müsste _)Danke
-
Du meinst sowas?
Dictonary<String,Command> commands = new Dictonary<String,Command>() void Factory() { commands.Add("Befehl1",new Command1()); commands.Add("Befehl2",new Command2()); .... } Command GetCommand(String befehl) { if(commands.ContainsKey(befehl) { return commands[befehl]; } else { throw new Exception("Der Befehl '"+ befehl +"' existiert nicht"); } }
-
Er wollte, dass in der Map nur der Typ der Klasse gespeichert wird. Und er dann dynamisch von diesem Typ ein Objekt erstellt und dieses zurückgibt. In deinem Fall bekommt er ja für 2 gleiche Anfragen "Befehl1" zweimal das gleiche Objekt zurück, was aber nicht der Sinn eines Factory-Patterns ist. Ich kann allerdings auch keinen Lösungsvorschlag bieten.
-
public interface CommandCreator { Command Create(); } // Folgende Klasse dient als Beispiel, wie man trotzdem das Verhalten von Andorxors Lösung nachbildet. public class SingleCommandCreator : CommandCreator { private Command command; public SingleCommandCreator(CommandCreator commandCreator) { command = commandCreator.Create(); } public Command Create() { return command; } } // Falls man nicht für jeden Command einen eigenen CommandCreator schreiben will, kann man auch eine "generische" Variante durch Reflection verwenden. Das Problem ist hierbei halt, dass der entsprechende Konstruktor vorhanden sein muss. public class ReflectionCommandCreator : CommandCreator { private Type commandType; public ReflectionCommandCreator(Type commandType) { if (commandType == null) { throw new ArgumentNullException("commandType"); } this.commandType = commandType; } public Command Create() { return Activator.CreateInstance(commandType) as Command; } } public class Factory { private Dictionary<string, CommandCreator> commands = new Dictionary<string, CommandCreator>(); public void Register(string key, CommandCreator commandCreator) { commands.Add(key, commandCreator); } public Command GetCommand(string key) { if (!commands.ContainsKey(key)) { return null; } return commands[key].Create(); } } // ... factory.Register("command1", new ReflectionCommandCreator(typeof(CustomCommand)); factory.Register("command2", new SingleCommandCreator(new FooBarCommandCreator()); factory.Register("command3", new BlubberblaseCommandCreator());
-
Danke, Danke, Danke...das letzte war genau das was ich gesucht hatte.
Ich hab mich für die ReflectionCommandCreator methode entschieden (is einfach, da es eine Menge Befehle werden, und jedesmal ein CommandCreator wollte ich nicht _)
Einen Nachtrag hab ich aber noch:
public class ReflectionCommandCreator : CommandCreator { public Command Create() { [b]object[] Params = {Argument1, ..., ArgumentX};[/b] return Activator.CreateInstance(commandType, Params) as Command; } }
Dann kann man auch einen Konstruktor mit Werten füllen. (Falls das nochmal jemanden interessiert)
-
// nachdem du anscheinend doch auch oftmal Parameter benötigst .. public class ReflectionCommandCreator : CommandCreator { private Type commandType; private object[] arguments; public ReflectionCommandCreator(Type commandType) : this(commandType, null) { // ... } public ReflectionCommandCreator(Type commandType, params object[] arguments) { if (commandType == null) { throw new ArgumentNullException("commandType"); } this.commandType = commandType; this.arguments = arguments; } public Command Create() { return Activator.CreateInstance(commandType, arguments) as Command; } } // weitere Möglichkeit um CommandCreator Implementierungen zu verringern // siehe Prototype Pattern public class PrototypeCommandCreator : CommandCreator { private CloneableCommand prototype; public PrototypeCommandCreator(CloneableCommand prototype) { if (prototype == null) { throw new ArgumentNullException("prototype"); } this.prototype = prototype; } public Command Create() { return prototype.Clone(); } }