JavaWorld für OO: Get / Setter vs Builder

8

Hintergrund:

Ich fand diesen Artikel auf JavaWorld, wo Allen Holub eine Alternative zu Getters / Setter erklärt, die das Prinzip beibehält, dass die Implementierung eines Objekts versteckt werden sollte (sein Beispielcode kann auch unten gefunden werden).

Es wird erklärt, dass die Klassen Name / EmployeeId / Money einen Konstruktor haben sollten, der eine einzelne Zeichenkette nimmt - die Begründung ist, dass wenn Sie es als int eingeben und später ändern müssen a long , müssen Sie alle Verwendungen der Klasse ändern, und mit diesem Muster müssen Sie nicht.

Frage 1:

Ich frage mich: verschiebt das nicht einfach das Problem auf das Parsen der Parameter String , die herumgeworfen werden? Wenn beispielsweise der gesamte Code mit dem EmployeeId (erhalten von Exporter ) das String in ein int zerlegt und Sie plötzlich long Werte exportieren, müssen Sie genau so viele Verwendungen ändern. .. und wenn du beginnst, es als long zu analysieren, dann musst du vielleicht zu double wechseln (auch wenn das für IDs keinen Sinn ergibt) ... und wenn du nicht sicher sein kannst, was zu analysieren ist String in, Sie können nichts implementieren .

Frage 2:

Abgesehen von dieser Frage habe ich noch eine andere: Ich weiß, dass der Artikel über sieben Jahre alt ist. Könnte mich jemand auf einige aktuelle Übersichten über OO-Design und insbesondere auf Ideen bezüglich der Getter / Setter- und Implementationsdebatte verweisen?

Listing 1. Mitarbeiter: Der Builder-Kontext

%Vor%     
wen 03.08.2011, 13:35
quelle

4 Antworten

7

Frage 1 : String Parsing scheint seltsam. IMHO können Sie nur so viel tun, um zukünftige Erweiterungen vorwegzunehmen. Entweder verwenden Sie von Anfang an einen long -Parameter, um sicher zu sein, oder überlegen, später weitere Konstruktoren hinzuzufügen. Alternativ können Sie eine erweiterbare Parameterklasse einführen. Siehe unten.

Frage 2 : Es gibt verschiedene Szenarien, in denen das Builder-Muster nützlich sein kann.

  • Komplexe Objekt-Erstellung

    Wenn Sie mit sehr komplexen Objekten arbeiten, die viele Eigenschaften haben dass Sie bei der Objekterstellung vorzugsweise nur einmal setzen würden, indem Sie dies tun Regelmäßige Konstruktoren können schwer lesbar werden, weil der Konstruktor dies tut habe eine lange Liste von Parametern. Die Veröffentlichung als API ist kein guter Stil weil jeder die Dokumentation sorgfältig lesen und sicherstellen muss Sie verwechseln Parameter nicht.

    Wenn Sie stattdessen einen Baumeister anbieten, müssen Sie nur mit dem (privaten) Konstruktor nimmt alle Argumente, aber die Konsumenten Ihrer Klasse können Verwenden Sie viel besser lesbare individuelle Methoden.

    Setter sind nicht dasselbe, weil sie es Ihnen ermöglichen würden, Objekte zu ändern Eigenschaften nach seiner Erstellung.

  • Erweiterbare API

    Wenn Sie nur einen Konstruktor mit mehreren Parametern für Ihre Klasse und später veröffentlichen Entscheiden Sie, dass Sie eine neue (optionale) Eigenschaft hinzufügen müssen (zB in einer späteren Version Ihrer Software) Sie müssen einen zweiten Konstruktor erstellen, der identisch ist mit dem ersten, aber Nimmt einen weiteren Parameter. Sonst - wenn Sie es nur zum bestehenden hinzufügen würden Konstruktor - Sie würden die Kompatibilität mit dem vorhandenen Code unterbrechen.

    Mit einem Builder fügen Sie einfach eine neue Methode für die neue Eigenschaft mit allen vorhandenen hinzu Code ist immer noch kompatibel.

  • Unveränderbarkeit

    Die Softwareentwicklung ist stark auf parallele Ausführung ausgerichtet mehrere Threads. In solchen Szenarien ist es am besten, Objekte zu verwenden, die nicht können geändert werden, nachdem sie erstellt wurden (unveränderliche Objekte), weil diese kann keine Probleme mit gleichzeitigen Updates von mehreren Threads verursachen. Das ist Warum Setter sind keine Option.

    Wenn Sie nun die Probleme der öffentlichen Multiparameter-Konstruktoren vermeiden wollen, das lässt Bauherren eine sehr bequeme Alternative.

  • Lesbarkeit ("Fluent API")

    Builder-basierte APIs können sehr einfach zu lesen sein, wenn die Methoden des Builders sind genial benannt, können Sie mit Code kommen, der fast wie englische Sätze liest.

Im Allgemeinen sind Builder ein nützliches Muster, und abhängig von der Sprache, die Sie verwenden, sind sie entweder sehr einfach zu verwenden (z. B. Groovy) oder etwas mühsamer (z. B. in Java) für den Anbieter einer API. Für die Verbraucher können sie jedoch genauso einfach sein.

    
Daniel Schneller 03.08.2011, 14:04
quelle
2

Sie können Builders übersichtlich gestalten. ;) Ich habe oft geschrieben Builder von Hand mühsam und fehleranfällig gefunden.

Es kann gut funktionieren, wenn Sie ein Datenmodell haben, das Ihre Data-Value-Objekte und ihre Builder (und Marshaller) generiert. In diesem Fall glaube ich, Builders zu verwenden ist es wert.

    
Peter Lawrey 03.08.2011 13:46
quelle
2

Es gibt viele Probleme mit Konstruktoren, die Argumente annehmen (zum Beispiel können Sie das Objekt nicht in mehreren Schritten erstellen). Auch wenn Sie viele Argumente benötigen, werden Sie schließlich über die Reihenfolge der Parameter verwirrt.

Die neueste Idee ist die Verwendung einer " fließenden Benutzeroberfläche ". Es funktioniert mit Setter, die this zurückgeben. Oft wird set im Methodennamen weggelassen. Jetzt können Sie schreiben:

%Vor%

Dies hat mehrere Vorteile:

  1. Es ist sehr gut lesbar.
  2. Sie können die Reihenfolge der Parameter ändern, ohne etwas zu brechen
  3. Es kann einwertige und mehrwertige Argumente ( address ).
  4. verarbeiten

Der größte Nachteil ist, dass Sie nicht mehr wissen, wann die Instanz bereit ist, verwendet zu werden.

Die Lösung besteht darin, viele Komponententests durchzuführen oder eine "init ()" - oder "done ()" -Methode hinzuzufügen, die alle Prüfungen durchführt und ein Flag "diese Instanz ist richtig initialisiert" setzt.

Eine andere Lösung ist eine Factory, die die tatsächliche Instanz in einer Methode build() erstellt, die die letzte in der Kette sein muss:

%Vor%

Moderne Sprachen wie Groovy machen dies zu einem Sprachfeature:

%Vor%     
Aaron Digulla 03.08.2011 13:58
quelle
0

Wenn Sie für ein Objekt einen Konstruktor benötigen (Factories auf ähnliche Weise berücksichtigen), erzwingen Sie, dass der Code, der Ihr Objekt verwendet, die grundlegenden Anforderungen an den Konstruktor übergibt. Je expliziter, desto besser. Sie können die optionalen Felder, die später gesetzt werden (injiziert), mit einem Setter belassen.

    
n0rm1e 03.08.2011 13:47
quelle