Oft sehe ich die Implementierung des Builder-Musters (in Java) folgendermaßen:
public class Foo {
private Foo(FooBuilder builder) {
// get alle the parameters from the builder and apply them to this instance
}
public static class FooBuilder {
// ...
public Foo build() {
return new Foo(this); // <- this part is what irritates me
}
}
}
Beispiele auch hier:
- /programming/25130510/builder-pattern-in-java
- https://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html
Warum führen Menschen die starke (gegenseitige) Abhängigkeit zwischen Builder und Typ ein, um zu bauen?
EDIT: Ich meine, ich weiß, dass der Builder naturgemäß an die Klasse gebunden ist, aus der ich eine Instanz erstellen möchte ( FooBuilder -> Foo
). Was ich frage ist: Warum gibt es die Notwendigkeit für den umgekehrten Fall ( Foo -> FooBuilder
)
Im Gegenteil, ich sehe (seltener) Implementierungen, die einen neuen Zeitpunkt für Foo
die Erstellung des Builders erstellen und die Felder für die Instanz festlegen, in der Foo
die entsprechenden Builder-Methoden aufgerufen werden. Ich mag diesen Ansatz besser, weil er immer noch eine fließende API hat und die Klasse nicht an ihren Builder bindet. Gibt es einen Nachteil dieses anderen Ansatzes?
Foo
Konstruktor öffentlich ist?Antworten:
Es läuft darauf hinaus, niemals einen Foo in einem halb konstruierten Zustand zu haben
Einige Gründe, die mir in den Sinn kommen:
Der Builder ist von Natur aus an die Klasse gebunden, die er konstruiert. Sie können sich die Zwischenzustände des Builders als Teilanwendung des Konstruktors vorstellen, sodass Ihr Argument, dass er zu gekoppelt ist, nicht überzeugend ist.
Durch die Übergabe des gesamten Builders können Felder in MyClass endgültig sein, was das Nachdenken über MyClass erleichtert. Wenn die Felder nicht endgültig sind, können Sie genauso gut fließende Setter haben wie ein Builder.
quelle
Der Builder enthält veränderbare Felder, die mit Methoden festgelegt wurden. Die tatsächliche Klasse (
Foo
) kann dann unveränderlichefinal
Felder aus dem Builder erstellen .Der Builder ist also eine Stateful-Klasse.
Aber der Baumeister hätte auch anrufen können
new Foo(x, y, z)
. Das wäre meiner Meinung nach eher einseitig und besser. Da dann das Anti-Pattern, ein FooBuilder-Feld oder so nicht möglich wäre. Andererseits garantiert der FooBuilder eine gewisse Integrität der Daten.Auf der anderen Seite spielt FooBuilder zwei Rollen: zum Erstellen mit einer fließenden API und zum Präsentieren von Daten für den Konstruktor. Es ist eine Ereignistypklasse für den Konstruktor. In einem überentwickelten Code könnten die Konstruktorparameter in einigen FooConstructorParams beibehalten werden.
quelle
Weil ein "Builder" normalerweise verwendet wird, um das "Teleskopkonstruktorproblem" zu lösen, insbesondere im Zusammenhang mit unveränderlichen Klassen. Unter diesem Link finden Sie ein umfassendes Beispiel.
Überlegen Sie, wie die Alternativen aussehen würden:
Oder:
Insbesondere für unveränderliche Klassen gibt es keine Alternative, wenn Sie keinen Konstruktor mit einer Reihe von Parametern möchten.
quelle
foo.Attribute1=par1
es möglich ist,Foo
ist es definitiv veränderlich, auch in Java. Unveränderliche Klassen müssen jegliche Mutation ihres Zustands nach der Konstruktion verbieten, weder durch Setter noch durch Methoden, die ihren Zustand mutieren, noch durch Aufdecken von Attributen öffentlicher Mitglieder.