Frage

Ich las Joshua Blochs " Effective Java Programming Language Guide ".
Er erklärt statische Factory-Methoden verwendet werden könnten, zu vermeiden unnötigen doppelte Objekte .
Ich habe nicht ganz verstanden dies.
Könnte jemand erklären?

War es hilfreich?

Lösung

Ein reales Beispiel:

Java unterstützt sowohl primitive und Objekttypen ein Byte darzustellen. Wenn Sie ein primitives Objekt umwandeln Sie etwas tun könnten, wie:

Byte b = new Byte( (byte) 65);

Butt Das würde eine neue Instanz für jeden Anruf erstellen. Stattdessen tun Sie:

Byte b = Byte.valueOf( (byte) 65);

bei jedem Aufruf der Methode valueOf () wird die gleiche Instanz eines Byte-Objekts zurückgibt, die den Byte-Wert 65.

Nach 10000 das erste Beispiel ruft haben 10000 Objekte geschaffen würden, während die zweite nur ein, weil Byte-Klasse verfügt über einen internen Cache von Byte Objekte, die alle Zahlen zwischen -128 und 127.

Andere Tipps

Alle Antworten auf nicht-Duplizierung scheinen auf dem Singletonmuster zu konzentrieren, die ein gutes Beispiel für Nicht-Duplizierung ist, aber ein schlechtes Muster im allgemeinen Fall zu verwenden. Meiner Ansicht nach sollte eine bestimmte Anwendung haben null auf Singletons darin, mit einer Vorliebe für Null. Aber das hat wenig mit nicht zu schaffen unneccesary Objekte zu tun.

Sie stattdessen eine Anwendung, die eine Menge von Date-Objekten zu machen hat. Es macht so viele Date-Objekte, die die Konstruktion der Date-Objekte wird eine negative Auswirkung auf die Leistung haben. Anstatt also den Konstruktor des Date-Objekts aufrufen, wird der Code Refactoring nur Daten über eine Factory-Methode zu erstellen. Innerhalb dieser Fabrik Verfahrens wird eine Karte geprüft angefordert, um zu sehen, ob das Datum wurde bereits erstellt. Wenn ja, dann wird das gleiche Objekt aus der Karte zurückgegeben. Andernfalls wird ein neues wird in der Karte erstellt, setzen und zurückgegeben.

Was ist zu verwirrend zu sein scheint, Sie ist, wie durch die Fabrik-Methode aufrufen Sie ein doppeltes Objekt verhindern zu schaffen. Nur durch eine Factory-Methode ruft nicht wirklich etwas ändern. Was die Fabrik Aufruf erlaubt ist für Code zu übernehmen und eine Entscheidung über das Erstellen des Objekts machen. Wenn neue Aufruf, kann keine solche Entscheidungen getroffen werden.

Siehe auch diese Frage für einige mehr Einblick in das Muster und was es für verwendet werden.

Wenn Sie einen Konstruktor aufrufen, es wird wieder immer ein neues Objekt (es sei denn, eine Ausnahme ausgelöst wird). Statische Factory-Methoden, oder jede Art von Fabrik was das betrifft, haben nicht immer ein neues Objekt zurück. Zum Beispiel ist die getInstance() Methode auf dem traditionellen Singleton-Entwurfsmuster eine Factory-Methode, die immer genau die gleiche Objekt zurückgibt. Es gibt Fälle, in denen man manchmal diese Art der Sache tun wollen, ob es sich um ein Objekt zu erzwingen ist nur einmal instanziiert werden, oder irgendeine Art von Objekt Pool, etc. Im Allgemeinen zu schaffen, ich denke, das ist ein Rand Grund für die Verwendung statische Factory-Methoden. Der Hauptzweck ist schön genannte Pseudo-Konstrukteuren zu erstellen.

Hier ist ein (etwas albern) Beispiel für statische Factory-Methoden unter Verwendung von gut genannten Pseudo-Konstrukteuren zu machen. Betrachten Sie diese Klasse:

class Person {

   public Person(Role role) {
      setRole(role);
   }

   ...
}

Ohne statische Factory-Methoden, könnte man so etwas tun:

Person employee = new Person(Role.EMPLOYEE);
Person manager = new Person(Role.MANAGER);

Stattdessen könnten Sie statische Factory-Methoden erstellen:

class Person {

   public static Person newEmployee() {
      return new Person(Role.EMPLOYEE);
   }

   public static Person newManager() {
      return new Person(Role.MANAGER);
   }

   private Person(Role role) {
      setRole(role);
   }

   ...
}

und Sie könnten stattdessen etwas tun, wie folgt aus:

Person employee = Person.newEmployee();
Person manager = Person.newManager();

Das kann nicht ein gutes Beispiel sein, aber eine komplexere Konstruktor oder eines mit einem weniger beschreibenden Parametern in Betracht ziehen. Manchmal Weg geht der Factory-Methode macht den Code klar. Es gibt natürlich auch Nachteile ...

Was die Objekterstellung zu begrenzen, sollten Sie einige seltsame Einschränkung wie kann es nie mehr als ein CEO sein:

class Person {

   private static Person singletonCEO = new Person(Role.CEO);

   public static Person newCEO() {
      return singletonCEO;
   }

   ...
}

und wie es wäre erstellt werden:

Person ceo1 = Person.newCEO();
Person ceo2 = Person.newCEO();

assertThat(ceo1, is(ceo2)); // JUnit 4.x

Ich hoffe, diese Beispiele helfen.

Die Factory-Methode Muster kann mal nützlich sein, wenn es nicht notwendig ist, eine zu schaffen neue Instanz eines Objekts, um eine Aktion auszuführen.

Hier sind ein paar allgemeine Fälle, die ich von denen eine statische Factory-Methode denken kann, die das gleiche Objekt zurückgibt nützlich sein kann:

  1. Das Objekt teuer erstellen - Es gibt eine Menge der Verarbeitung ist, wenn das Objekt instanziiert wird, so dass das Objekt mehr als einmal instanziieren ist nicht wünschenswert. (Dies bezieht sich auch auf die Singletonmuster .)

  2. Das Objekt hält keinen Staat -. Wenn es keinen Staat Unterschied zwischen den Fällen ist, gibt es keinen guten Zweck ein neues Objekt jedes Mal erstellen

Wikipedia-Seite über die Factory-Methode Muster mehr Informationen zu diesem Thema hat.


Lassen Sie uns ein konkretes Beispiel einen Blick darauf werfen.

Die DateFormat -Klasse verwendet, die getInstance statische Methode Rückkehr eine DateFormat Instanz, die verwendet werden kann, eine Date in eine voreingestellte Formatierung zu formatieren je nach locale der Maschine.

Da die DateFormat der zurückgegeben wird, wird die gleiche Formatierung für jede Datumsformatierung Aktion verwendet wird, gibt es keinen wirklichen Grund ist jedes Mal eine neue DateFormat Instanz zu schaffen.

Im Allgemeinen ist die Art und Weise dies umgesetzt wird, ist eine Instanz zu erstellen, wenn eine Instanz nicht bereits vorhanden ist, und halten Sie dann einen Verweis auf diese Instanz. Wenn die Instanz wieder benötigt wird, wird die Referenz zurückgegeben. (Dies ist in der Regel, wie das Singleton-Muster als auch umgesetzt wird.)

Zum Beispiel:

class MySingleInstanceObject {

  private MySingleInstanceObject instance;

  private MySingleInstanceObject() {
    // Initialize the object.
    // This may be expensive.
  }

  public MySingleInstanceObject getInstance() {
    if (instance == null) {
      instance = new MySingleInstanceObject();
    }

    return instance;
  }
}

(FYI, der obige Code ist ein Beispiel für einen Singleton. Es ist auch nicht Thread-sicher.)

Wenn ich mich gut erinnere, er gibt auch ein Beispiel in dem Buch. Betrachten Decimal. Null ist sehr oft verwendet. Also, wenn Sie die statische Factory-Methode Decimal.valueOf("0") nennen würde (weiß nicht, ob dies der eigentliche API ist, aber das spielt keine Rolle, aus Gründen der diesem Beispiel) wird es zurückgeben Sie eine Instanz der Dezimal reprezenting 0 und es wäre die gleiche Instanz für jeden Anruf. Die Umsetzung wäre so etwas wie dies:

public class Decimal {
    private static Decimal zero = new Decimal(0);

    public static Decimal valueOf(String s) {
        if (s.equals("0")) {
            return zero;
        } else {
            return new Decimal(parse(s)); // or whatever
        }

    // rest of the class
}

Beachten Sie, dass es nur eine einzige Instanz von Null ist, während für jede andere Zahl ein neues Objekt erstellt wird. Außerdem funktioniert dies mit Factory-Methoden, und Sie können nicht tun dies mit Konstrukteuren. Das ist, was Bloch versucht, darauf hinzuweisen, als Vorteil für die ehemaligen.

Und wie Yishai erwähnte, ist es nicht so eng zu Singleton verwendet. Wie Sie sehen können, können Sie viel Dezimal haben Objekte um. Stattdessen können Sie Factory-Methoden verwenden, um die volle Kontrolle über die Anzahl der Instanzen haben Sie erstellen. Deshalb ist es ein Werk genannt wird.

Ich konnte einige dieses Buch hier . Nach dem Lesen, was er schrieb scheint es, dass er sagt, was ist die statischen Factory-Methoden geben Ihnen mehr Flexibilität als Entwickler und ermöglicht es Ihnen, auch mit deutlicher zu sein, was zurückgegeben wird. Wenn Sie dies zu einem Konstruktor Kontrast kann der Konstruktor nicht Klarheit in Bezug auf das, was zurückgegeben wird. Zusätzlich können Sie Dinge tun, wie das Caching usw. in der statischen Factory-Methode, die ich dachte, war faszinierend. Dieser Ansatz scheint ein guter Ansatz, wenn Sie dieses Maß an Kontrolle und Flexibilität benötigen.

Der Punkt auf nicht zu schaffen unnötige doppelte Objekte kommen in, wenn Sie Caching verwenden möchten. Mit dieser statischen Fabrik Ansatz könnte man das gleiche Objekt auf jeden Aufruf der statischen Factory-Methode zurück.

ein Beispiel:

public class Person
{

   private Person(string firstName, string lastName)
   {
      this.FirstName = firstName;
      this.LastName = lastName;
   }

   public string FirstName {get; private set;}
   public string LastName {get; private set;}

   private static Dictionary<string, Person> objectPool = new Dictionary<string, Person>();
   private object lockObject = new object();

   public static Person CreatePerson(string firstName, string lastName)
   {
      var result = objectPool[firstName + lastName];
      Person person = null; 
      if (result != null)
      {
         return result
      }
      lock(lockObject)
      {
          person = new Person(firstName, lastName);
          objectPool.Add(firstName + lastName, person)
      }
      return person;
   }
}

Wenn Sie eine Factory-Klasse haben Objekt Instanziierungen zu erstellen, jedes Mal gehen, um ein Objekt zu erstellen, werden Sie auch die Factory-Klasse instanziiert müssen. Grundsätzlich würden Sie Vervielfältigungen dieser Fabrik Klasse werden zu schaffen.

Wenn es statisch ist, müssen Sie nur die eine Instanz der Fabrik verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top