Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Eigentlich wollte ich nur ein geeignetes UML Diagramm suchen.. dass mich dann aber stutzig machte.
Wieso der „abstrakte“ Creator? Kann mir jmd in plausibeler Form erklären welchen praktischen Nutzen es hätte auch diesen nur abstrakt anzugeben. Oder ist dies nur ein „nice 2 have“ für Änderungen an der Objekterstellung.
So ganz kapier' ich die Frage nicht: Man verwendet die abstrakte Factory, weil die konkrete Ausprägung ja nicht bekannt ist. Man kann ja keine Methode machen
Code:
void addNewCar(VW_or_BMW_creator c)
{
list.add(c.createCar());
}
sondern muss eine Methode machen
Code:
void addNewCar(carCreator c)
{
list.add(c.createCar());
}
der man dann entweder einen VWcreator oder einen BMWcreator übergibt. Man könnte statt der abstrakten Klasse auch ein interface verwenden, das nur die Methode "createCar" anbietet... meintest du das?
Richtig das ist mir klar....
nur red ich hier nicht von der abstract factory sondern der factory method die
eigentlich für die Entscheidung zwischen verschiedenen Objekten fällen sollte (Zumindest
war ich bis vor 5 min noch davon überzeugt).
Wenn ich ein Objekt will und auf Objektgruppen keinen Wert lege ist diese Klasse doch völlig unnütz oder
seh ich da was zu flach?
Beispiel:
Ich habe ein ConnectionInterface und 2 (oder mehr) Connections die dieses implementieren (bsp OracleConnection).
Nun reicht es mir doch die Factory konkret zu implementieren.
Code:
public class ConnectionFactory {
public Connection getConnection(String connectionString){
String[] parts = connectionString.split(":");
if(parts[0].equals("ora")){
return new OracleConnection();
} else if(parts[0].equals("sqls")){
return new SQLServerConnection();
} else if(parts[0].equals("pgre")){
return new PostgreConnection();
} else if(parts[0].equals("mysql")){
return new MySQLConnection();
} else {
throw new RuntimeException();
}
}
}
Hm - beim Versuch deine Aussage "...factory method die eigentlich für die Entscheidung zwischen verschiedenen Objekten fällen sollte"
mit dem verlinkten Artikel zu "mtachen", fand ich als passende Stelle nur den Satz im ersten Absatz: "...überlässt aber die Entscheidung darüber, welche konkrete Klasse instanziiert werden soll, seinen Unterklassen."
Vielleicht ist das ... unpräzise formuliert: Es ist (möglicherweise, aber) NICHT notwendigerweise so, dass in den Unterklassen dann eine Entscheidung im Sinne einer if-Abfrage getroffen wird.
Die "Entscheidung" liegt vielmehr darin, welche implementierung der Factory verwendet wird.
Vielleicht hilft eine Websuche nach "Dependency Injection" auch zum Verständnis. Mit Hilfe einer abstrakten Fabrik kann man die Verantwortung für die Erstellung der Connection an jemand anderen weiterreichen - nämlich den, der das Programm verwenden (bzw. die Connection bereitstellen) will.
In deinem Connection-Beispiel wird jetzt die Entscheidung auf Basis des übergebenen Strings getroffen. Das ist aber u.U. unflexibel. Ich kenn mich nicht mit Datenbanken aus, deswegen ist das Beispiel jetzt künstlich und vielleicht unpassend, aber verdeutlicht hoffentlich das Problem: Wenn jetzt jemand eine Access-Datenbank ansprechen will, dann funktioniert das mit deiner Connection-Factory nicht. DU müßtest DEINE ConnectionFactory erweitern, nur weil "irgedein Depp" eine Access-Datenbank ansprechen will.
Man würde - als Beispiel - also nicht sowas schreiben wie
void doIt(String connectionString) { ... }
sondern
void doIt(ConnectionFactory connectionFactory) { ... }
Damit könnte derjenige, der eine Access-Connection verwenden will, einfach eine passende Implementierung der Factory erstellen, und die an deine Methode weiterreichen
Code:
// Methode, die die Factory verwendet:
void doIt(ConnectionFactory factory)
{
Connection connection = factory.getConnection();
readDataFromConnection(connection);
}
// Verwendung für dich - zum Beispiel mit deiner bisherigen
// Factory-Implementierung, die die Entscheidung auf Basis
// eines Strings trifft
doIt(new GeneralConnectionFactory("ora:blalba:1521:user:pw1234"));
Erweitert für den, der eine Access-Connection braucht:
Code:
class AccessConnectionFactory extends AbstactConnectionFactory (oder implements ConnectionFactory)
{
public Connection getConnection()
{
AccessConnection c = new AccessConnection();
c.doSomeVerySpecificInitializationThatIsONLYRequiredForTheAccessConnection();
return c;
}
}
// Verwendung
doIt(new AccessConnectionFactory());
Nochmal: Das ist ein bißchen gestelzt, aber vielleicht wird ja der Vorteil im Vergleich zu einer festen Implementierung, die hoch-spezifische Strings abfragt, damit deutlich...
Implementation 2 - When the Creator class is a Concreate class:
In this type of implementation, the concrete Creator uses the factory method primarily for flexibility. It says "Create objects in a separate operation so that subclasses can change the way they are created". This ensures that, if necessary, designers of subclasses can change the class of objects their parent class instantiates.
Ist also eine Implementationssache was auch erklärt warum ich mir doch relativ sicher
war dass ich den Sinn dieses Patterns eigetnlich verstanden hab :wink:
Deine Methode die du erklärst führt in meiner Überlegung nur zur unnötigen Unterklassenbildung (10 Factories die eigentlich nich gebraucht werden) deswegen war es für mich anfangs nich ganz nachvollziehbar.
Das, was du ursprünglich hattest, ähnelte eher dem, was dort als Implementation 3 beschrieben ist - aber auch nur teilweise ... (abhängig davon, in welchem Zusammenhang du deine Klasse verwenden wolltest).
Ggf. hat man natürlich bei allen Alternativen die Möglichkeit, von der Creator-Klasse zu erben und die passende Methode zu überschreiben. So hätte z.B. bei deiner ConnectionFactory jemand sagen können
Code:
public class ExtendedConnectionFactory extends ConnectionFactory
{
public Connection getConnection(String connectionString)
{
if (connectionString.startsWith("access")) return new AccessConnection();
else return super.getConnection(connectionString);
}
}