¿Los argumentos nombrados reemplazan el patrón de construcción?

20

Cuando se usa un lenguaje que admite argumentos con nombre y opcionales, ¿el patrón de construcción ya no tiene un uso práctico?

Constructor:

new Builder(requiredA, requiredB).setOptionalA("optional").Build();

Argumentos opcionales / nombrados:

new Object(requiredA, requiredB, optionalA: "optional");
Paul Nikonowicz
fuente
3
¿Cómo manejas 20 argumentos opcionales? No hay ningún problema que el Generador deba resolver hasta que se agrande. En el punto que ha descrito aquí, tiene dos constructores (y no crearía un generador para ese pequeño problema).
1
Incluso con argumentos opcionales: si el constructor tiene más de 2 argumentos, estoy a favor de usar un objeto de valor para encapsular la configuración. Lo mismo ocurre con las interfaces fluidas y el generador: cualquier cosa mayor que 3 sería sustituida por un objeto de valor.
Thomas Junk

Respuestas:

21

Los constructores son más útiles cuando su objeto necesita muchos argumentos / dependencias para ser útil, o si desea permitir muchas formas diferentes de construir el objeto.

Fuera de mi cabeza, puedo imaginar que alguien quiera "construir" objetos en un juego 3D como este:

// Just ignore the fact that this hypothetical god class is coupled to everything ever
new ObjectBuilder(x, y, z).importBlenderMesh("./meshes/foo")
                          .syncWithOtherPlayers(serverIP)
                          .compileShaders("./shaders/foo.vert", "./shaders/foo.frag")
                          .makeDestructibleRigidBody(health, weight)
                          ...

Yo diría que este ejemplo es más legible con los métodos de creación que he creado justo ahora que con los parámetros opcionales:

new Object(x, y, z, meshType: MESH.BLENDER,
                    meshPath: "./meshes/foo",
                    serverToSyncWith: serverIP,
                    vertexShader: "./shaders/foo.vert",
                    physicsType: PHYSICS_ENGINE.RIGID_DESTRUCTIBLE,
                    health: health,
                    weight: weight)
                    ...

En particular, la información implícita en los nombres de los métodos de creación debe reemplazarse por más parámetros, y es mucho más fácil olvidarse de un parámetro en un grupo de parámetros estrechamente relacionados. De hecho, falta el sombreador de fragmentos, pero no lo notarías a menos que supieras buscarlo.


Por supuesto, si su objeto solo requiere de uno a cinco argumentos para construir, no hay necesidad de involucrar el patrón de construcción, ya sea que haya nombrado o no parámetros opcionales.

Ixrec
fuente
No compro tus argumentos. Si los nombres de los métodos de creación son maravillosos, también puede usarlos para los nombres de los parámetros. Si los parámetros están estrechamente relacionados, colóquelos en un pequeño constructor de objetos.
user949300
@ user949300 Creo que te has perdido la parte importante del punto, que es que los métodos de construcción aquí describen las relaciones entre los parámetros que se pierden si solo tienes un montón de parámetros opcionales. En el ejemplo del constructor de Ixrec, "salud" y "peso" son, lógicamente, parte de la configuración corporal destructible, pero esa relación se pierde en la versión de argumento opcional.
Jules
1
no si uno de los parámetros opcionales es (cuerpo: nuevo DestructibleRigidBody (salud, peso), ...)
Weyland Yutani
@Jules. Lo que dijo Weyland: hacer un pequeño constructor bien nombrado para peso y altura.
user949300
8

Además de lo que dijo Ixrec, los constructores o los parámetros nombrados por el método no le permitirán tener su objeto en un estado por construir en el que aún pueda modificarse antes de construirlo. Esta es la belleza del generador, donde puede delegar partes de su construcción a diferentes métodos o clases juntas:

var myThingBuilder = new ThingBuilder("table");
myThingBuilder.setAttribute(Attributes.Legs, 4);

inventoryManager.setPrices(myThingBuilder);

// inventory manager
var availableCheapestMaterial = getMaterial();
myThingBuilder.setMaterial(availableCheapestMaterial);

Básicamente, también puede lanzar su constructor alrededor de su sistema hasta que esté listo para construir el objeto final, lo que le permite disminuir la cantidad de conocimiento que su constructor-consumidor necesita tener.

Alfa
fuente
No entiendo tu último párrafo. Si "lanza su generador alrededor del sistema hasta que esté listo", tiene demasiado conocimiento del sistema. Su ThingBuilder conoce los atributos, es modificado misteriosamente por InventoryManager y conoce los materiales. No veo cómo eso está disminuyendo el conocimiento.
user949300
@ user949300 Piense en cómo sería sin el constructor viajando a través del sistema. Te verías obligado a tener una clase con un gran factor de despliegue, y eso es solo necesario para construir la Cosa. (Por supuesto, suponiendo que su clase no concentre todo el conocimiento, esto es lo que queríamos evitar en primer lugar). Ahora, si esta clase tiene alguna otra responsabilidad, está creando una clase enorme, rompiendo S en SÓLIDO . Si esa es la única responsabilidad, te estás haciendo un ThingBuilder.
Alpha
1

Depende de lo que esté haciendo con el constructor.

Si está utilizando el generador solo para establecer (y variar) las propiedades del objeto y (diferir) la creación del objeto, se puede reemplazar con parámetros con nombre.

Al reemplazar el constructor, es posible que tenga el compromiso de legibilidad / uso que mencionó @Ixrec (o puede que no lo tenga, depende de lo que esté haciendo con el constructor).

Sin embargo, si su constructor hace más que simplemente mantener las propiedades y cada paso de construcción involucra lógica, no puede ser reemplazado.

MockBuilder es un ejemplo en el que no se puede reemplazar con parámetros con nombre. De la página:

La lógica en los pasos de creación no se puede reemplazar con parámetros con nombre

rvazquezglez
fuente
-5

El patrón de construcción es esencial cuando se trabaja con objetos inmutables. Hay muchos beneficios al trabajar con objetos inmutables, especialmente al hacer que su programa sea más robusto al ejecutarse en un entorno concurrente (es decir, subprocesos)

codedabbler
fuente
3
Sí, los constructores son excelentes para trabajar con objetos inmutables complejos (o incluso con objetos mutables; debe asegurarse de que el objeto esté en un estado coherente antes de poder usarlo). Dicho esto, new Integer(42), new BigDecimal("42.000")y new String("foobar")son todos los constructores a inmutables que ... bueno, un constructor sería innecesariamente compleja para estos casos. Por lo tanto, un constructor no es esencial para trabajar con inmutables cuando los constructores pueden funcionar igual de bien.
Sí, un constructor se puede usar con objetos inmutables, eso no se niega. Pero la pregunta original era si el patrón Builder tiene algún uso práctico aparte de los argumentos opcionales y mi respuesta fue aclarar esto.
codedabbler
2
La pregunta original no dice nada sobre objetos inmutables. Se trata de parámetros con nombre y la relación con ellos con Builders. Su respuesta es sobre el constructor y su relación con los objetos inmutables. Me cuesta ver cómo su respuesta responde a la pregunta.