¿Cuáles son algunos comunes , ejemplos del mundo real de utilizar el Builder? ¿Qué te compra? ¿Por qué no solo usar un patrón de fábrica?
java
design-patterns
builder
Charles Graham
fuente
fuente
Respuestas:
La diferencia clave entre un constructor y una IMHO de fábrica, es que un constructor es útil cuando necesita hacer muchas cosas para construir un objeto. Por ejemplo, imagine un DOM. Tienes que crear muchos nodos y atributos para obtener tu objeto final. Se utiliza una fábrica cuando la fábrica puede crear fácilmente todo el objeto dentro de una llamada de método.
Un ejemplo de uso de un generador es la creación de un documento XML. He utilizado este modelo al crear fragmentos HTML, por ejemplo, podría tener un generador para crear un tipo específico de tabla y podría tener los siguientes métodos (no se muestran los parámetros) :
Este constructor entonces escupió el HTML para mí. Esto es mucho más fácil de leer que recorrer un gran método de procedimiento.
Echa un vistazo a Builder Pattern en Wikipedia .
fuente
A continuación se presentan algunas razones para argumentar el uso del patrón y el código de ejemplo en Java, pero es una implementación del Patrón de construcción cubierto por la Banda de cuatro en los patrones de diseño . Las razones por las que lo usaría en Java también son aplicables a otros lenguajes de programación.
Como Joshua Bloch dice en Effective Java, 2nd Edition :
En algún momento, todos hemos encontrado una clase con una lista de constructores donde cada adición agrega un nuevo parámetro de opción:
Esto se llama el patrón de constructor telescópico. El problema con este patrón es que una vez que los constructores tienen 4 o 5 parámetros de largo, se hace difícil recordar el orden requerido de los parámetros , así como también qué constructor particular puede desear en una situación dada.
Una alternativa que tiene al Patrón de constructor telescópico es el Patrón de JavaBean donde llama a un constructor con los parámetros obligatorios y luego llama a cualquier configurador opcional después de:
El problema aquí es que debido a que el objeto se crea a través de varias llamadas, puede estar en un estado inconsistente a la mitad de su construcción. Esto también requiere mucho esfuerzo adicional para garantizar la seguridad del hilo.
La mejor alternativa es usar el Patrón de generador.
Tenga en cuenta que Pizza es inmutable y que los valores de los parámetros están todos en una sola ubicación . Debido a que los métodos de establecimiento del generador devuelven el objeto generador, pueden encadenarse .
Esto da como resultado un código fácil de escribir y muy fácil de leer y comprender. En este ejemplo, el método de compilación podría modificarse para verificar los parámetros después de que se hayan copiado del generador al objeto Pizza y arrojar una IllegalStateException si se ha proporcionado un valor de parámetro no válido. Este patrón es flexible y es fácil agregarle más parámetros en el futuro. Realmente solo es útil si va a tener más de 4 o 5 parámetros para un constructor. Dicho esto, podría valer la pena en primer lugar si sospecha que puede agregar más parámetros en el futuro.
He tomado prestado mucho sobre este tema del libro Effective Java, 2nd Edition de Joshua Bloch. Para obtener más información sobre este patrón y otras prácticas eficaces de Java, lo recomiendo encarecidamente.
fuente
new Pizza.Builder(12).cheese().pepperoni().bacon().build();
Pizza.Builder(12).cheese().pepperoni().bacon().build();
necesitaría recompilar su código o tener una lógica innecesaria si solo necesita un poco de pepperoni pizzas Como mínimo, también debe proporcionar versiones parametrizadas como @Kamikaze Mercenary originalmente sugerido.Pizza.Builder(12).cheese(true).pepperoni(false).bacon(false).build();
. Por otra parte, nunca hacemos pruebas unitarias, ¿verdad?Considera un restaurante. La creación de la "comida de hoy" es un patrón de fábrica, porque usted le dice a la cocina "consígueme la comida de hoy" y la cocina (fábrica) decide qué objeto generar, en base a criterios ocultos.
El generador aparece si solicita una pizza personalizada. En este caso, el camarero le dice al chef (constructor) "¡Necesito una pizza; agréguele queso, cebolla y tocino!" Por lo tanto, el constructor expone los atributos que debe tener el objeto generado, pero oculta cómo configurarlos.
fuente
La clase .NET StringBuilder es un gran ejemplo de patrón de generador. Se utiliza principalmente para crear una cadena en una serie de pasos. El resultado final que obtienes al hacer ToString () siempre es una cadena, pero la creación de esa cadena varía de acuerdo con las funciones que se usaron en la clase StringBuilder. En resumen, la idea básica es construir objetos complejos y ocultar los detalles de implementación de cómo se está construyendo.
fuente
b.append(...).append(...)
antes de llamar finalmentetoString()
. Cita: infoq.com/articles/internal-dsls-javaPara un problema de subprocesos múltiples, necesitábamos construir un objeto complejo para cada subproceso. El objeto representaba los datos que se procesaban y podía cambiar según la entrada del usuario.
¿Podríamos usar una fábrica en su lugar? si
¿Por qué no lo hicimos nosotros? Constructor tiene más sentido, supongo.
Las fábricas se utilizan para crear diferentes tipos de objetos que son del mismo tipo básico (implementar la misma interfaz o clase base).
Los constructores construyen el mismo tipo de objeto una y otra vez, pero la construcción es dinámica, por lo que se puede cambiar en tiempo de ejecución.
fuente
Lo usa cuando tiene muchas opciones con las que lidiar. Piensa en cosas como jmock:
Se siente mucho más natural y es ... posible.
También hay construcción xml, construcción de cadenas y muchas otras cosas. Imagina si
java.util.Map
hubiera puesto como constructor. Podrías hacer cosas como esta:fuente
Mientras revisaba el marco de Microsoft MVC, pensé en el patrón del generador. Encontré el patrón en la clase ControllerBuilder. Esta clase es para devolver la clase de fábrica del controlador, que luego se utiliza para construir un controlador concreto.
La ventaja que veo al usar el patrón de construcción es que puede crear una fábrica propia y conectarla al marco.
@Tetha, puede haber un restaurante (Framework) dirigido por un chico italiano que sirve pizza. Para preparar pizza, el tipo italiano (Object Builder) usa Owen (Factory) con una base de pizza (clase base).
Ahora el chico indio se hace cargo del restaurante del italiano. El restaurante indio (Framework) sirve dosa en lugar de pizza. Para preparar dosa, el tipo indio (constructor de objetos) usa Sartén (Fábrica) con una Maida (clase base)
Si observa el escenario, la comida es diferente, la forma en que se prepara la comida es diferente, pero en el mismo restaurante (bajo el mismo marco). El restaurante debe construirse de tal manera que pueda soportar cocina china, mexicana o de cualquier tipo. El creador de objetos dentro del marco facilita agregar el tipo de cocina que desee. por ejemplo
fuente
Siempre me disgustó el patrón Builder como algo difícil de manejar, molesto y muy a menudo abusado por programadores menos experimentados. Es un patrón que solo tiene sentido si necesita ensamblar el objeto a partir de algunos datos que requieren un paso posterior a la inicialización (es decir, una vez que se recopilan todos los datos, haga algo con ellos). En cambio, en el 99% del tiempo, los constructores simplemente se usan para inicializar a los miembros de la clase.
En tales casos, es mucho mejor simplemente declarar los establecedores de
withXyz(...)
tipo dentro de la clase y hacer que devuelvan una referencia a sí mismo.Considera esto:
Ahora tenemos una clase única ordenada que gestiona su propia inicialización y hace casi el mismo trabajo que el constructor, excepto que es mucho más elegante.
fuente
Otra ventaja del generador es que si tiene una Fábrica, todavía hay algo de acoplamiento en su código, porque para que la Fábrica funcione, tiene que conocer todos los objetos que puede crear . Si agrega otro objeto que podría crearse, deberá modificar la clase de fábrica para incluirlo. Esto también sucede en Abstract Factory.
Con el constructor, por otro lado, solo tiene que crear un nuevo constructor concreto para esta nueva clase. La clase de director permanecerá igual, porque recibe al constructor en el constructor.
Además, hay muchos sabores de constructor. Kamikaze Mercenary`s da otro.
fuente
fuente
Sobre la base de las respuestas anteriores (juego de palabras), un excelente ejemplo del mundo real es el soporte incorporado de Groovy
Builders
.MarkupBuilder
StreamingMarkupBuilder
SwingXBuilder
Ver constructores en la documentación de Groovy
fuente
Utilicé el constructor en la biblioteca de mensajería local. El núcleo de la biblioteca estaba recibiendo datos del cable, recopilándolos con la instancia de Builder, luego, una vez que Builder decidió que tenía todo lo necesario para crear una instancia de Mensaje, Builder.GetMessage () estaba construyendo una instancia de mensaje utilizando los datos recopilados del cable.
fuente
Echa un vistazo a InnerBuilder, un complemento IntelliJ IDEA que agrega una acción 'Generador' al menú Generar (Alt + Insertar) que genera una clase de generador interno como se describe en Java efectivo
https://github.com/analytically/innerbuilder
fuente
Cuando quise usar el XMLGregorianCalendar estándar para mi XML para objetar la clasificación de DateTime en Java, escuché muchos comentarios sobre lo pesado y engorroso que era usarlo. Estaba tratando de controlar los campos XML en las estructuras xs: datetime para administrar la zona horaria, milisegundos, etc.
Así que diseñé una utilidad para construir un calendario XMLGregorian desde un GregorianCalendar o java.util.Date.
Debido a dónde trabajo, no puedo compartirlo en línea sin contenido legal, pero aquí hay un ejemplo de cómo lo usa un cliente. Resume los detalles y filtra parte de la implementación de XMLGregorianCalendar que se usa menos para xs: datetime.
Por supuesto, este patrón es más un filtro, ya que establece campos en el xmlCalendar como indefinidos para que se excluyan, todavía lo "construye". He agregado fácilmente otras opciones al generador para crear una estructura xs: date y xs: time y también para manipular las compensaciones de zona horaria cuando sea necesario.
Si alguna vez has visto código que crea y usa XMLGregorianCalendar, verás cómo esto hizo que sea mucho más fácil de manipular.
fuente
Un gran ejemplo del mundo real es usar cuando la unidad prueba sus clases. Utiliza constructores sut (sistema bajo prueba).
Ejemplo:
Clase:
Prueba:
Sut Builder:
fuente
CustomAuthenticationService
clase?