Digamos de alguna manera que todos los objetos se crean de esta manera $ obj = CLASS :: getInstance (). Luego inyectamos dependencias usando setters y realizamos la inicialización inicial usando $ obj-> initInstance (); ¿Hay problemas o situaciones reales que no puedan resolverse si no usamos constructores?
Ps la razón para crear objetos de esta manera, es que podemos reemplazar la clase dentro de getInstance () de acuerdo con algunas reglas.
Estoy trabajando en PHP, si eso importa
object-oriented-design
class-design
Axel Foley
fuente
fuente
Respuestas:
Yo diría que esto dificulta severamente su espacio de diseño.
Los constructores son un gran lugar para inicializar y validar los parámetros pasados. Si ya no puede usarlos para eso, entonces la inicialización, el manejo del estado (o simplemente negar el constructor de objetos "rotos") se vuelve mucho más difícil y parcialmente imposible.
Por ejemplo, si cada
Foo
objeto necesita un,Frobnicator
entonces podría verificar en su constructor si elFrobnicator
no es nulo. Si quitas el constructor, entonces es más difícil de verificar. ¿Verifica en cada punto donde se utilizaría? ¿En uninit()
método (externalizando efectivamente el método del constructor)? ¿Nunca lo compruebas y esperas lo mejor?Si bien es probable que aún pueda implementar todo (después de todo, todavía está completo), algunas cosas serán mucho más difíciles de hacer.
Personalmente, sugiero buscar en la inyección de dependencia / inversión de control . Estas técnicas también permiten cambiar las clases de implementación concretas, pero no impiden escribir / usar constructores.
fuente
HttpClient
entonces verifica si ese parámetro no es nulo). Y si no se cumplen esas restricciones, puede generar una excepción. Eso no es realmente posible con el enfoque de construir y establecer valores.init()
, lo cual es completamente posible, aunque esto simplemente impone una carga de mantenimiento más.2 ventajas para los constructores:
Los constructores permiten que los pasos de construcción de un objeto se realicen atómicamente.
Podría evitar un constructor y usar setters para todo, pero ¿qué pasa con las propiedades obligatorias como sugirió Joachim Sauer? Con un constructor, un objeto posee su propia lógica de construcción para garantizar que no haya instancias no válidas de dicha clase .
Si crear una instancia de
Foo
requiere que se establezcan 3 propiedades, el constructor podría tomar una referencia a las 3, validarlas y lanzar una excepción si no son válidas.Encapsulamiento
Al confiar únicamente en los colocadores, la carga recae en el consumidor de un objeto para construirlo adecuadamente. Podría haber diferentes combinaciones de propiedades que sean válidas.
Por ejemplo, cada
Foo
instancia necesita una instancia deBar
como propiedadbar
o una instancia deBarFinder
como propiedadbarFinder
. Puede usar cualquiera de los dos. Puede crear un constructor para cada conjunto válido de parámetros y aplicar las convenciones de esa manera.La lógica y la semántica de los objetos viven dentro del objeto mismo. Es buena encapsulación.
fuente
Sí, puedes vivir sin constructores.
Claro, puede terminar con un montón de código de placa de caldera duplicado. Y si su aplicación es de cualquier escala, es probable que pase mucho tiempo tratando de localizar el origen de un problema cuando ese código repetitivo no se use de manera consistente en toda la aplicación.
Pero no, no "necesita" estrictamente sus propios constructores. Por supuesto, tampoco estrictamente 'necesita' clases y objetos.
Ahora, si su objetivo es usar algún tipo de patrón de fábrica para la creación de objetos, eso no es mutuamente exclusivo de usar constructores al inicializar sus objetos.
fuente
La ventaja de usar constructores es que hacen que sea más fácil asegurarse de que nunca tendrá un objeto no válido.
Un constructor le brinda la oportunidad de establecer todas las variables miembro del objeto en un estado válido. Cuando se asegura de que ningún método mutador pueda cambiar el objeto a un estado no válido, nunca tendrá un objeto no válido, lo que lo salvará de muchos errores.
Pero cuando se crea un nuevo objeto en un estado no válido y debe llamar a algunos establecedores para ponerlo en un estado válido en el que pueda usarse, se arriesga a que un consumidor de la clase olvide llamar a estos establecedores o los llame incorrectamente y terminas con un objeto no válido.
Una solución alternativa podría ser crear objetos solo a través de un método de fábrica que verifica la validez de cada objeto que crea antes de devolverlo a la persona que llama.
fuente
Creo que estás haciendo esto más difícil de lo que debe ser. Podemos inyectar dependencias perfectamente a través del constructor, y si tiene muchas de ellas, simplemente use una estructura similar a un diccionario para que pueda especificar cuáles quiere usar:
Y dentro del constructor, puede garantizar la coherencia de esta manera:
$args
luego se puede usar para establecer miembros privados según sea necesario.Cuando se realiza por completo dentro del constructor de esta manera, nunca habrá un estado intermedio donde
$obj
exista pero no se inicialice, como lo habría en el sistema descrito en la pregunta. Es mejor evitar tales estados intermedios, porque no puede garantizar que el objeto siempre se use correctamente.fuente
En realidad estaba pensando en cosas similares.
La pregunta que hice fue "¿Qué hace el constructor, y es posible hacerlo de manera diferente?" Llegué a esas conclusiones:
Asegura que algunas propiedades se inicialicen. Al aceptarlos como parámetros y configurarlos. Pero esto podría ser implementado fácilmente por el compilador. Simplemente anotando los campos o propiedades como "obligatorios", el compilador comprobará durante la creación de la instancia si todo está configurado correctamente. La llamada para crear la instancia probablemente sería la misma, simplemente no habría ningún método constructor.
Asegura que las propiedades sean válidas. Esto podría lograrse fácilmente mediante una condición de afirmación. Nuevamente, simplemente anotaría las propiedades con las condiciones correctas. Algunos idiomas ya hacen esto.
Alguna lógica de construcción más compleja. Los patrones modernos no recomiendan hacer eso en el constructor, pero proponen usar métodos o clases especializados de fábrica. Entonces, el uso de constructores en este caso es mínimo.
Entonces para responder a su pregunta: Sí, creo que es posible. Pero requeriría algunos grandes cambios en el diseño del lenguaje.
Y acabo de notar que mi respuesta es bastante OT.
fuente
Sí, puede hacer casi todo sin usar constructores, pero esto es claramente una pérdida de beneficios de los lenguajes de programación orientados a objetos.
En las lenguas modernas (Voy a hablar aquí sobre C # qué programa I en) puede limitar partes de código que se pueden ejecutar solamente en un constructor. Gracias a lo cual puedes evitar errores torpes. Una de esas cosas es el modificador de solo lectura :
Según lo recomendado por Joachim Sauer anteriormente, en lugar de usar el
Factory
patrón de diseño, lea sobreDependency Injection
. Recomendaría leer Inyección de dependencias en .NET por Mark Seemann .fuente
Instanciar un objeto con un tipo dependiendo de los requisitos es absolutamente posible. Podría ser el objeto en sí mismo, utilizando variables globales del sistema para devolver un tipo específico.
Sin embargo, tener una clase en el código que puede ser "Todo" es el concepto de tipo dinámico . Personalmente, creo que este enfoque crea inconsistencia en su código, hace que los complejos de prueba * y "el futuro se vuelva incierto" con respecto al flujo del trabajo propuesto.
* Me refiero al hecho de que las pruebas deben considerar primero el tipo, luego el resultado que desea lograr. Entonces estás creando una gran prueba anidada.
fuente
Para equilibrar algunas de las otras respuestas, afirmando:
y
Tales declaraciones a veces implican la suposición de que:
Pero esto no es del todo cierto. La mayoría de los idiomas no tienen una regla en contra de que un constructor pase
this
(oself
como lo llame el idioma) a código externo. Tal constructor cumple completamente con la regla establecida anteriormente, y sin embargo, corre el riesgo de exponer los objetos semi-construidos a código externo. Es un punto menor pero fácil de pasar por alto.fuente
Esto es algo anecdótico, pero generalmente reservo constructores para el estado esencial para que el objeto sea completo y utilizable. Salvo cualquier inyección de setter, una vez que se ejecuta el constructor, mi objeto debería ser capaz de realizar las tareas requeridas.
Cualquier cosa que pueda diferirse, la dejo fuera del constructor (preparación de valores de salida, etc.). Con este enfoque, siento que no uso constructores para nada, pero la inyección de dependencia tiene sentido.
Esto también tiene el beneficio adicional de cablear su proceso de diseño mental para no hacer nada prematuramente. No inicializará ni ejecutará una lógica que quizás nunca termine siendo utilizada porque, en el mejor de los casos, todo lo que está haciendo es la configuración básica para el trabajo por delante.
fuente