Domanda

La seguente classe:

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;
    }

}

potrebbe essere usato in un modello di costruttore e dopo che è stato costruito, è efficacemente immutabile, perché ogni proprietà può essere impostata una sola volta. Questo è:

Pizza pizza = new Pizza().setIngredients(something).setPrice(somethingelse);

Tuttavia, Pizza non è sicuro: non ci sono garanzie che il filo B veda gli ingredienti che sono stati impostati dal thread A. Ci sono alcuni modi per risolverlo:

  • Fare membri final. Ma poi non puoi usare un modello di costruttore.
  • Sincronizzare l'accesso ai membri. Ma questo sembra spreco, perché sono scritti solo una volta.
  • Falli volatile. Si sente spreco, come la sincronizzazione.
  • Uso AtomicReference.
  • Eccetera.?

La mia domanda è: qual è il modo migliore per dire al JVM che un membro della classe non cambierà dopo che è stato chiamato qualche metodo? Dovrei semplicemente sincronizzare l'accesso ad esso e fidarmi che JVM ottimizzerà il blocco? Sembra solo sprecato, perché io sapere che il membro dovrebbe comportarsi come è final dopo che è stato impostato. Non ci sono soluzioni migliori?

È stato utile?

Soluzione

Il modello Builder di solito significa che il costruttore è un oggetto separato. In questo caso puoi creare campi dell'oggetto in costruzione final, e inizializzali nel costruttore chiamato dall'oggetto Builder:

Pizza pizza = 
    new PizzaBuilder()
        .setIngredients(something)
        .setPrice(somethingelse)
        .build(); 

In alternativa, è possibile garantire una pubblicazione sicura del Pizza oggetto. Si noti che i idiomi di pubblicazione sicuri sono applicati al campo che contiene un riferimento all'oggetto pubblicato, non ai campi di quell'oggetto stesso. Ad esempio, se pizza è un campo di un oggetto, puoi farcela volatile o sincronizzare l'accesso ad esso: garantirebbe una pubblicazione sicura di Pizza oggetto assegnato a quel campo.

Altri suggerimenti

Se i valori dei membri non dovrebbero mai cambiare, il modello migliore sarebbe avere un Pizza costruttore che prende come parametri Ingredients e Price, e non hanno alcun metodo di setter sull'oggetto. Davvero non è utile avere un setSomething() Metodo che lancia un'eccezione dopo la prima volta che viene chiamato.

Considera come il String La classe funziona. Una volta che hai istanziato a String Con un po 'di testo, il valore del testo non può essere modificato. L'unico modo per ottenere un String con un valore diverso è costruirne uno nuovo. Sembra che sia quello che vuoi qui.

L'uso di questo modello evita anche il problema della sincronizzazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top