Pregunta

La siguiente clase:

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

}

podría usarse en un patrón de constructor, y después de que se haya construido, es efectivamente inmutable, porque cada propiedad se puede configurar solo una vez. Eso es:

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

Sin embargo, Pizza no es seguro del hilo: no hay garantías de que el hilo B ve los ingredientes que el hilo colocó en él A. Hay algunas formas de solucionarlo:

  • Hacer miembros final. Pero entonces no puedes usar un patrón de constructor.
  • Sincronice el acceso a los miembros. Pero esto parece desperdicio, porque están escritos solo una vez.
  • Hazlos volatile. Se siente residuos, como la sincronización.
  • Usar AtomicReference.
  • Etc.?

Mi pregunta es, ¿cuál es la mejor manera de decirle al JVM que un miembro de la clase no cambiará después de que se haya llamado a algún método? ¿Debo sincronizar el acceso a él y confiar en que el JVM optimizará el bloqueo? Simplemente se siente desperdicio, porque yo saber que el miembro debería comportarse como es final Después de que esté listo. ¿No hay mejores soluciones?

¿Fue útil?

Solución

El patrón de constructor generalmente significa que el constructor es un objeto separado. En este caso, puede hacer campos del objeto que se está construyendo final, e inicializarlos en el constructor llamado por el objeto Builder:

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

Alternativamente, puede garantizar una publicación segura del Pizza objeto. Tenga en cuenta que los modismos de publicación seguros se aplican al campo que contiene una referencia al objeto que se publica, no a los campos de ese objeto en sí. Por ejemplo, si pizza es un campo de algún objeto, puedes hacerlo volatile o sincronizar el acceso a él: garantizaría una publicación segura de Pizza objeto asignado a ese campo.

Otros consejos

Si los valores de los miembros nunca pretenden cambiar, el mejor patrón sería tener un Pizza constructor que toma como sus parámetros Ingredients y Price, y no tienen métodos establecidos en el objeto en absoluto. Realmente no es útil tener un setSomething() Método que arroja una excepción después de la primera vez que se llama.

Considere cómo el String clase funciona. Una vez que hayas instanciado un String Con algún texto, el valor del texto no se puede cambiar. La única forma de obtener un String con un valor diferente es construir uno nuevo. Parece que eso es lo que quieres aquí.

El uso de este patrón también evita el problema de sincronización.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top