Gewährleistung der Sichtbarkeit des Speichers mit dem Bauherren/Fabrikmuster
-
28-10-2019 - |
Frage
Die folgende Klasse:
class Pizza {
Ingredients ingredients;
Price price;
public setIngredients(Ingredients ing) {
if (ingredients != null) {
throw new IllegalStateException();
}
ingredients = ing;
return this;
}
public setPrice(Price p) {
if (price != null) {
throw new IllegalStateException();
}
price = p;
return this;
}
}
Könnte in einem Builder -Muster verwendet werden, und nachdem es gebaut wurde, ist es effektiv unveränderlich, weil jede Eigenschaft nur einmal festgelegt werden kann. Das ist:
Pizza pizza = new Pizza().setIngredients(something).setPrice(somethingelse);
Jedoch, Pizza
ist nicht fadensicher: Es gibt keine Garantie dafür, dass Faden B die Zutaten sehen, die durch den Thread A eingestellt wurden. Es gibt einige Möglichkeiten, sie zu beheben:
- Mitglieder machen
final
. Aber dann können Sie kein Builder -Muster verwenden. - Synchronisieren Sie den Zugriff auf Mitglieder. Aber das scheint wie Abfall, weil sie nur einmal geschrieben sind.
- Mach sie
volatile
. Fühlt Abfall wie Synchronisation. - Verwenden
AtomicReference
. - Etc.?
Meine Frage ist, was ist der beste Weg, um dem JVM zu sagen, dass sich ein Klassenmitglied nicht ändert, nachdem eine Methode aufgerufen wurde? Sollte ich nur den Zugriff darauf synchronisieren und darauf vertrauen, dass die JVM das Schloss optimieren wird? Es fühlt sich nur verschwenderisch an, weil ich kennt dass das Mitglied sollte verhalten sich so wie es ist final
Nachdem es gesetzt ist. Gibt es keine besseren Lösungen?
Lösung
Builder -Muster bedeutet normalerweise, dass Builder ein separates Objekt ist. In diesem Fall können Sie Felder des zu erstellenden Objekts erstellen final
, und initialisieren Sie sie im Konstruktor, das vom Builder -Objekt aufgerufen wurde:
Pizza pizza =
new PizzaBuilder()
.setIngredients(something)
.setPrice(somethingelse)
.build();
Alternativ können Sie eine sichere Veröffentlichung der sicherstellen Pizza
Objekt. Beachten Sie, dass sich sichere Veröffentlichungen an das Feld angewendet werden, das einen Verweis auf das veröffentlichte Objekt enthält, nicht auf die Felder dieses Objekts selbst. Zum Beispiel wenn pizza
ist ein Feld eines Objekts, Sie können es schaffen volatile
oder den Zugriff synchronisieren - es würde eine sichere Veröffentlichung von sicherstellen Pizza
Objekt diesem Feld zugewiesen.
Andere Tipps
Wenn sich die Mitgliedswerte nie ändern sollen, wäre das bessere Muster eine Einführung von a Pizza
Konstruktor, der als Parameter dauert Ingredients
und Price
, und haben überhaupt keine Settermethoden auf dem Objekt. Wirklich, es ist nicht nützlich, eine zu haben setSomething()
Methode, die nach dem ersten Mal aufgerufen wird.
Überlegen Sie, wie das String
Klasse funktioniert. Sobald Sie instanziiert haben a String
Mit einem Text kann der Textwert nicht geändert werden. Der einzige Weg, um eine zu bekommen String
Mit einem anderen Wert ist es, eine neue zu konstruieren. Es scheint, als ob Sie hier wollen.
Die Verwendung dieses Musters vermeidet auch das Synchronisationsproblem.