Der Builder implementiert Cloneable und überschreibt clone (). Anstatt jedes Feld des Builders zu kopieren, behält die unveränderbare Klasse einen privaten Clone des Builders bei. Dies macht es einfach, einen neuen Builder zurückzugeben und leicht modifizierte Kopien einer unveränderlichen Instanz zu erstellen.
So kann ich gehen
%Vor%Die Cloneable-Schnittstelle soll etwas kaputt sein, aber verstößt dies gegen eine gute Java-Coding-Praxis, gibt es irgendwelche Probleme mit diesem Konstrukt?
%Vor%Im Allgemeinen hat die aus dem Builder erstellte Klasse keine speziellen Kenntnisse des Builders. Das Unveränderliche hätte einen Konstruktor, der den Wert für foo und bar liefert:
%Vor%Der Builder wäre eine separate Klasse:
%Vor%Wenn Sie möchten, können Sie dem MyImmutable-Builder eine statische Methode hinzufügen, um mit einer vorhandenen MyImmutable-Instanz zu beginnen:
%Vor%Ich habe diesen Ansatz noch nie gesehen, aber es sieht so aus, als würde es gut funktionieren.
Im Grunde macht es das Builder-Muster relativ einfach zu implementieren, auf Kosten eines etwas höheren Laufzeit-Overheads (zusätzliche Objekte + Klonen + eine Indirektionsstufe in Accessor-Funktionen, die kompiliert werden können oder nicht).
Eine mögliche Variation, die Sie vielleicht in Betracht ziehen sollten: Wenn Sie die Builder-Objekte selbst unveränderbar machen, müssen Sie sie nicht defensiv klonen. Dies könnte ein Gesamtgewinn sein, besonders wenn Sie Objekte viel häufiger erstellen, als Sie die Builder ändern.
Ihre Implementierung ähnelt der in Josh Blochs Effective Java 2nd Edition beschriebenen Implementierung.
Ein Streitpunkt wäre Ihre Methode build()
. Wenn ein einzelner Builder eine unveränderbare Instanz erstellt, wäre es fair, den Builder erneut zu verwenden, wenn man bedenkt, dass die Arbeit erledigt ist? Die Vorsicht hier ist, dass, obwohl Sie ein unveränderliches Objekt erstellen, die Wandlungsfähigkeit Ihres Builders zu einigen eher "überraschenden" Fehlern führen kann.
Um dies zu korrigieren, wird empfohlen, dass die Erstellungsmethode die Instanz erstellen sollte und der Builder dann nicht in der Lage sein sollte, das Objekt erneut zu erstellen, sodass ein neuer Builder erforderlich ist. Obwohl die Kesselplatte langwierig erscheinen mag, überwiegen die später zu gewinnenden Vorteile die derzeit erforderlichen Anstrengungen. Die Implementierungsklasse kann dann eine Builder
-Instanz als Konstruktorparameter erhalten, aber der Builder sollte dann die Instanz den benötigten Status abrufen lassen, die Builder-Instanz freigeben und die endgültigen Verweise auf die fraglichen Daten beibehalten.
Tags und Links java immutability builder-pattern