2016-05-07 9 views
1

Wenn wir Abstract Factory Pattern verwenden, wir haben in der Regel FactoryMaker Klasse, die eine getFactory Funktion hat, in der wir Argument übergeben, und wir haben switch oder if-else Logik in der Funktion auf dem übergebenen Parameter, die Fabrik zu entscheiden, zurückgeben. Erzeugt übergebenen Parameter eine Enumeration oder ein Objekt, und dann wird die Logik, welche Factory in diesen Objekten zurückgegeben wird, besser sein. Zum Beispiel:Abstrakt Factory Design: wenn sonst mit Enum Ersetzen

Lassen Sie uns sagen, das wir unsere Fabrikhersteller, die enum CountryCode übergeben werden, um Fabrik zu entscheiden.

 

    public class FacoryMaker { 

     public final static FacoryMaker fctry= new FacoryMaker(); 

     public static RetailFactory getFactory(CountryCode code){ 
      RetailFactory rt = null; 
      if(code == CountryCode.UK){ 
       rt = new UKFactory(); 
      } 
      if(code == CountryCode.US){ 
       rt = new USFactory(); 
      } 
      return rt; 
     } 
    } 

dieser Stattdessen werden wir haben:

 

    public class FacoryMaker { 

     public final static FacoryMaker fctry= new FacoryMaker(); 

     public static RetailFactory getFactory(CountryCode code){ 
      return code.getFactory(); 
     } 
    } 

und Enum wird wie folgt geändert werden:

 

    public enum CountryCode { 
     US(){ 
      @Override 
      public RetailFactory getFactory() { 
       return new USFactory(); 
      } 
     }, 
     UK(){ 
      @Override 
      public RetailFactory getFactory() { 
       return new UKFactory(); 
      } 
     }; 
     public abstract RetailFactory getFactory(); 
    } 

Aber ich sehe nicht, dies in der Regel folgt. Wieso ist es so? Warum können wir den übergebenen Parameter nicht immer zu einem Objekt machen und die Logik innerhalb des Objekts, von dem die Fabrik kommt, bekommen? Kann es unter irgendeinem abstrakten Fabrikdesign scheitern? Es sieht sehr allgemein aus. Dadurch ist es sogar möglich, den Fabrikhersteller zu entfernen und das Objekt direkt zu verwenden, um die Factory-Instanz zu erhalten.

Antwort

0

Ich denke, dass Abstract Factory ein allgemeines Muster für alle OOP-Sprachen ist. Wenn Leute es beschreiben, sollten sie eine allgemeine Implementierung zeigen, die in all diesen Sprachen angewendet werden kann. Dann folgen die Menschen dem Muster, sie folgen der generellen Implementierung.

Und Ihre Implementierung verwendet Enum, die speziell in Java, aber nicht in anderen OOP-Sprachen unterstützt wird.

+0

Enum ist auch ein Objekt. So können wir Objekte für solche Fälle erstellen und Implementierungen in ihnen haben. Das wird von allen OOP-Sprachen unterstützt, oder? –

+0

Es wird den Unterschied haben. Enum könnte hier sowohl als Konstante für die Parameterübergabe als auch als Objekt für Details der Factory-Implementierung verwendet werden.Wenn Sie eine Klasse verwenden, ist Ihr Übergabeparameter ebenfalls ein Objekt dieser Klasse. Das bedeutet, dass Sie Details der Fabrikimplementierung im Voraus kennen müssen und diese dann an die Methode übergeben müssen. Wenn Sie bereits über die Details der Factory-Implementierung Bescheid wussten, warum müssen Sie das abstrakte Fabrikmuster verwenden? –

0

Sehr oft in der Praxis, Factory-Methoden wissen nicht im Voraus die Implementierungen. Die implementierenden Klassen sind möglicherweise zum Zeitpunkt der Erstellung der Factory nicht vorhanden. Dies ist beispielsweise der Fall in Service-Provider-Frameworks wie dem Java Database Connectivity API (JDBC). JDBC definiert die Schnittstellen, die Service Provider implementieren müssen, aber die konkreten Implementierungen sind nicht im Voraus bekannt. Dieses Framework ermöglicht das spätere Hinzufügen von Implementierungen, z. B. für Datenbanktreiber neuer Schnittstellendatenbanken. Das Service-Provider-Framework enthält eine Provider-Registrierungs-API zum Registrieren von Implementierungen (z. B. DriverManager.registerDriver) und eine Servicezugriffs-API für Clients zum Abrufen einer Instanz des Service (z. B. DriverManager.getConnection). Es ist üblich, die Service-Implementierung mittels Reflektion zu instantiieren (zB Class.forName("org.blah.Driver")).

Ihr Beispiel ist anders. Sie kennen alle von Ihnen beabsichtigten Implementierungsklassen. Und Sie erwägen (noch) nicht die Pluggability anderer Implementierungen. Ob Sie die Instanzen mit einem switch oder einem enum, erstellen, macht es keinen großen Unterschied. Beide Alternativen sind in Ordnung, gleichwertig. Eine andere verwandte Alternative ist, dass die verschiedenen Methoden in Collections tun, zum Beispiel Collections.emptyList(), Collections.singletonList(...), und so weiter. Die Implementierungen werden nicht durch einen Schalter entschieden, sondern haben explizite Namen durch Verwendung spezieller Methoden.

Wenn Sie Implementierungen Ihrer Schnittstellen verwenden möchten, die nicht im Voraus bekannt sind und in Ihrer Fabrik nicht fest codiert sind, sollten Sie in Frameworks von Service Providern wie JDBC schauen.

Aber ich sehe nicht, dass dies allgemein befolgt wird. Wieso ist es so?

Ihre Technik funktioniert nur, weil Sie alle Implementierungen von RetailFactory im Voraus kennen. In Frameworks wie JDBC sind alle Implementierungen von Driver, Connection usw. nicht im Voraus für alle Datenbanken bekannt, so dass die Verwendung einer solchen Technik mit einer einzigen Enumeration, die auf alle Implementierungen verweist, nicht möglich und nicht skalierbar ist. Sie verwenden also einen anderen Mechanismus, um Implementierungen zur Laufzeit dynamisch zu registrieren und zu laden.

Warum können wir den übergebenen Parameter nicht immer ein Objekt machen und haben die Logik innerhalb des Objekts welcher Fabrik zu bekommen?

Sie können. Wenn Sie kein dynamisches Laden von Implementierungen wie JDBC benötigen (und wahrscheinlich auch nicht), hat Ihre Art der Verwendung von Enums einige Vorteile. Zum Beispiel, Ihre ursprüngliche Implementierung tut rt = ..., die nicht so gut ist wie return .... Ein solcher "Fehler" ist mit Ihrer enum Lösung nicht möglich. Auf der anderen Seite, wenn Sie dynamische laden möchten, dann macht die Verwendung eines enum nicht viel Sinn.

Die Grundlinie ist, es gibt keinen großen Unterschied zwischen den beiden Alternativen, die Sie vorgestellt haben. Beide sind gut.

+0

Können Sie es genauer erklären? Oder ein Codebeispiel kann mir helfen, es richtig zu verstehen. –

+0

@PankajKumar Ich habe weitere Erklärungen hinzugefügt und versucht, Ihre Fragen direkter zu beantworten. Ich hoffe das hilft. – janos

0

Wenn Software entwerfen, ist ein Aspekt zu berücksichtigen ist, Separation of Concerns es klingt nicht sehr vernünftig mir ein CountryCode eine RetailFactory erstellen zu lassen. Beide Konzepte haben eine ziemlich geringe Kohäsion zueinander, was vermieden werden sollte.

Wenn Sie bereits einen Ländercode haben, warum benötigen Sie überhaupt eine Fabrik, was verhindert, dass Sie die Methode getFactory direkt aufrufen? Es macht einfach keinen Sinn.

Der CountryCode ist lediglich ein Hinweis auf die Methode getFactory des FactoryMaker, wie die Factory erstellt wird. Es kann den Ländercode sogar völlig ignorieren. Was ist, wenn es ein Land ohne RetailFactory gibt? Liefst du zurück null? eine DefaultFactory oder die Factory eines anderen Landes?

Natürlich ist es möglich es auf diese Weise zu tun, aber wenn man sich den Code ab jetzt ein halbes Jahr aussehen, können Sie denken, "Wtf? Warum zum Teufel habe ich die Fabrik in der Country Code erstellen? ! "

Außerdem scheint das erste Beispiel Ihnen zur Verfügung gestellten mehr eine Factory Method als eine Fabrik weil die FactoryMaker haupt nicht verwendet wird, zu sein.