Problema
Recientemente leí mucho sobre Singletons como malo y cómo la inyección de dependencia (que entiendo como "usar interfaces") es mejor. Cuando implementé parte de esto con devoluciones de llamada / interfaces / DI y adhiriéndome al principio de segregación de interfaz, terminé con un gran lío.
Las dependencias de un UI padre donde básicamente se combinaban todas las de sus hijos, por lo que cuanto más arriba estaba la jerarquía de un elemento de UI, más hinchado estaba su constructor.
En la parte superior de la jerarquía de la interfaz de usuario había una clase de aplicación, que contenía la información sobre la selección actual y una referencia a un modelo 3D que debe reflejar los cambios. ¡La clase de aplicación estaba implementando 8 interfaces, y esto fue solo alrededor de una quinta parte de los productos (/ interfaces) por venir!
Actualmente trabajo con un singleton que contiene la selección actual y los elementos de la interfaz de usuario que tienen una función para actualizarse. Esta función desliza hacia abajo el árbol de la interfaz de usuario y los elementos de la interfaz de usuario y luego accede al singleton de selección actual según sea necesario. El código me parece más limpio de esta manera.
Pregunta
¿Un singleton puede ser apropiado para este proyecto?
Si no, ¿hay una falla fundamental en mi pensamiento y / o implementación de DI que lo hace tan engorroso?
Información adicional sobre el proyecto
Tipo: Canasta de compras para apartamentos, con campanas y silbatos
Tamaño: 2 meses-hombre para código y
mantenimiento de la interfaz de usuario : No hay actualizaciones en ejecución, pero tal vez "versión 2.0" posterior
Entorno: Uso de C # en Unity, que usa una Entidad Sistema de componentes
En casi todos los casos, la interacción del usuario desencadena varias acciones. Por ejemplo, cuando el usuario selecciona un elemento
- la parte de la interfaz de usuario que muestra ese elemento y su descripción debe actualizarse. Para esto, también necesita obtener información de un modelo 3D para calcular el precio.
- más arriba en la interfaz de usuario, el precio total general debe actualizarse
- Es necesario invocar una función correspondiente en una clase en un modelo 3D para mostrar los cambios allí.
fuente
Respuestas:
Creo que la pregunta es un síntoma, no una solución.
Una solución buscando un problema; eso y malinterpretarlo probablemente está corrompiendo su diseño. ¿Has leído esta pregunta SO sobre DI vs Singleton, diferentes conceptos o no? Leí eso simplemente envolviendo un singleton para que el cliente no tenga que lidiar con un singleton. Es.solo.en.encapsulación.buena.buena. Creo que eso es perfecto.
Primero construya los bits más pequeños, luego páselos al constructor de la cosa a la que pertenecen y pase esa cosa más grande al constructor de la próxima cosa más grande ...
Si tiene problemas de construcción complejos, use el patrón de fábrica o de construcción. La conclusión es que la construcción compleja se incorporó a su propia clase para mantener otras clases ordenadas, limpias, comprensibles, etc.
Esto suena como la ausencia de capacidad extendida. Falta el diseño central y todo está repleto desde la parte superior. Debería haber más construcción ascendente, composición y herencia.
Me pregunto si su diseño es "muy pesado". Parece que estamos tratando de hacer que una clase sea todo o cualquier cosa que pueda ser. Y el hecho de que sea una clase de interfaz de usuario, no una clase de dominio empresarial, realmente me hace preguntarme sobre la separación de las preocupaciones.
Revise su diseño desde el principio y asegúrese de que exista una abstracción de producto sólida y básica sobre la que se pueda construir para hacer producciones de categorías más complejas o diferentes. Entonces es mejor que tenga colecciones personalizadas de estas cosas, de modo que tenga un lugar para poner la funcionalidad de "nivel de colección", como ese "tercer modelo" que menciona.
Gran parte de esto puede caber en clases de colección personalizadas. También puede ser una estructura de clase independiente en sí misma debido a la profundidad y complejidad. Estas dos cosas no son mutuamente excluyentes.
Lea sobre el patrón de visitante. Es la idea de tener conjuntos completos de funcionalidades conectadas de manera abstracta a diferentes tipos.
Diseño y DI
El 90% de toda la inyección de dependencia que alguna vez harás es pasar parámetros de constructor. Eso dice el quy que escribió el libro . Diseñe bien sus clases y evite contaminar ese proceso de pensamiento con una vaga noción sobre la necesidad de usar un contenedor DI. Si lo necesita, su diseño se lo sugerirá, por así decirlo.
Concéntrese en modelar el dominio de compra de apartamentos.
Evite el enfoque del diseño de Jessica Simpson : "No sé qué significa eso, pero lo quiero".
Los siguientes son simplemente incorrectos:
fuente
La "jerarquía de clases" es una especie de bandera roja. Hipotético: una página web con 5 widgets. La página no es un ancestro de ninguno de los widgets. Puede contener una referencia a esos widgets. Pero no es un antepasado. En lugar de la jerarquía de clases, considere usar composición. Cada uno de los 5 widgets se puede construir por sí solo, sin referencia a los otros widgets o la página superior. La página superior se construye con suficiente información para construir una página básica y diseñar los objetos de widget (Colección) que se le pasan. La página es responsable del diseño, etc., pero no de la construcción y la lógica de los widgets.
Una vez que usa composición, DI es su mejor amigo. DI le permite cambiar cada widget por cualquier versión o tipo de widget que defina en DI. La construcción de los widgets se captura en la DI y está separada de la página superior. Quizás incluso la composición de la Colección se pueda definir en su DI. La página superior realiza el diseño en función de los widgets que se le pasan, como debería. No se necesitan cambios en el constructor de la página superior. La página superior solo necesita la lógica para realizar el diseño de los widgets y pasar información a / desde el widget en función de las interfaces definidas.
En lugar de pasar a los oyentes por la cadena de composición, inyecte una colección de oyentes a los widgets que lo necesitan. Inyecte la colección en un editor para que puedan publicar en la colección. Inyecte la colección en los oyentes para que puedan agregarse a la colección. La colección atraviesa todos los objetos en la cadena de composición.
fuente