2011-02-01 18 views

Respuesta

11

El patrón GoF se enfoca en abstraer los pasos de la construcción de modo que variando el constructor puede obtener resultados diferentes mientras que el "constructor revisado" se enfoca en el problema de la complejidad innecesaria agregada por múltiples constructores. Entonces, el patrón GoF se trata más de abstracción y el patrón revisado es más acerca de la simplicidad (IMO).

Mire los ejemplos en http://en.wikipedia.org/wiki/Builder_pattern y http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html y debe quedar bastante claro.

10

Nota re Mikko's answer: Hansen's example tiene algunos problemas - o, al menos, diferencias con respecto a la versión de Bloch, aunque soy de la opinión de que la versión de Bloch es superior.

Específicamente:

En primer lugar, los campos Widget 's se encuentran en Builder.build() en lugar de en el Widget constructor, y por tanto, no (y no puede ser) final. Widget se dice que es inmutable, pero no hay nada que disuada a otro programador de agregar y agregar setters más tarde.

En segundo lugar, los comentarios en el método de compilación de Hansen dicen "la validación previa a la creación va aquí". Bloch (. EJ 2ed p.15) dice:

Es muy importante que [los invariantes] comprobarse después de copiar los parámetros del constructor para el objeto, y que se puede comprobar en los campos del objeto en lugar de la campos de construcción (Ítem 39).

Si le da la vuelta al artículo 39 (Pág. 185) que ver el razonamiento:

[Esto] protege la clase frente a los cambios en los parámetros de otro hilo durante la "ventana de vulnerabilidad" entre el momento en que se verifican los parámetros y la hora en que se copian.

Los campos en Widget son inmutables y no requieren ninguna copia defensiva, pero no obstante es más seguro sólo para pegarse al patrón correcto, en caso de que alguien viene y añade un o una matriz Date o algún mutable Collection tarde . (También protege contra el otro hilo modificar el Builder en medio de una llamada a build(), pero eso es una ventana muy estrecha de la seguridad por lo que probablemente es mejor sólo para asegurarse Builder s no son compartidos entre los hilos.)

Un más Blochlike versión sería:

public class Widget { 
    public static class Builder { 
     private String name; 
     private String model; 
     private String serialNumber; 
     private double price; 
     private String manufacturer; 

     public Builder(String name, double price) { 
      this.name = name; 
      this.price = price; 
     } 

     public Widget build() { 
      Widget result = new Widget(this); 

      // *Post*-creation validation here 

      return result; 
     } 

     public Builder manufacturer(String value) { 
      this.manufacturer = value; 
      return this; 
     } 

     public Builder serialNumber(String value) { 
      this.serialNumber = value; 
      return this; 
     } 

     public Builder model(String value) { 
      this.model = value; 
      return this; 
     } 
    } 

    private final String name; 
    private final String model; 
    private final String serialNumber; 
    private final double price; 
    private final String manufacturer; 

    /** 
    * Creates an immutable widget instance. 
    */ 
    private Widget(Builder b) { 
     this.name = b.name; 
     this.price = b.price; 
     this.model = b.model; 
     this.serialNumber = b.serialNumber; 
     this.manufacturer = b.manufacturer; 
    } 

    // ... etc. ... 
} 

todos los campos son ahora Widgetfinal, y todos se validan después de la construcción.

+0

¿Su ejemplo no le permitiría crear alguna instancia de Builder con propiedades falsas (o faltantes, inestables) y luego llamar a "nuevo Widget (myBogusBuilder)" y terminar con una instancia "inestable" de Widget? (por ejemplo, no validar que el precio debe ser al menos mayor que "1", ya que solo verificaría eso en el método build()) – Rafa

+0

Lo haría si el constructor de widgets fuera público, pero es privado. La única forma de llamarlo (desde fuera de la clase) es a través de build(). –

+1

oh, cierto; no me di cuenta de eso (voy a revisar mis gafas ...). gracias :) – Rafa

Cuestiones relacionadas