Pregunta ¿Qué deberíamos usar en lugar de una clase "manager" en un buen diseño de OOP?


Tengo problemas para diseñar mi motor de juego. Por ejemplo:

Cuando pienso en Recursos, Creo en una Administrador de recursos clase para administrar recursos en mi motor.

Esta clase obtiene varias responsabilidades:

  • Cargar recursos
  • Asigna recursos por un identificador.
  • Asegúrese de que los recursos se carguen solo una vez.
  • Recursos gratuitos no utilizados (usando smartpointers).

Esto funciona para mí, pero he leído en cada tutorial de diseño de OOP que los gerentes son ambiguo clases con alto acoplamiento y baja cohesión. Entiendo esto, y estoy de acuerdo, pero busqué casi todo el Internet para encontrar un claro ejemplo de una alternativa real a los gerentes pero no lo encontré.

Algunas personas explican, por ejemplo, que un ResourceManager se debe dividir en clases más pequeñas: A ResourceFactory, un ResourceCollection, un ResourceCache, un ResourceFacade...

Conozco todos estos patrones de diseño (Factory, Collection, Facade, etc.). Pero realmente no entiendo cómo se puede unir para crear un sistema de administración de recursos (fácil de administrar).

Mi pregunta es: ¿Hay algún tutorial o documento con un claro ejemplo? ¿Alguien puede explicar un ejemplo de este sistema? Te agradeceré si puedes escribir un pequeño ejemplo en C ++ u otro idioma similar.

¡Gracias de antemano por tu ayuda!


32
2017-11-01 11:47


origen


Respuestas:


Tal vez:

  • Cargar recursos -> ResourceLoader
  • Asignar recursos por un identificador -> ResourceMapper
  • Asegúrese de que los recursos se carguen solo una vez -> CachedResourceLoader / este usa el ResourceLoader cuando aún no lo tiene cargado
  • Recursos gratuitos no utilizados (usando smartpointers) ->? / No estoy seguro acerca de esto, pero cargar + descargar parece conceptos altamente coherentes

Obtenga información adicional en el comentario sobre "Recursos no utilizados":

Primero, aclaremos que solo tenemos 2 de los anteriores involucrados: ResourceMapper y CachedResourceLoader. Como la instancia de ResourceLoader se utiliza desde CachedResource, no está expuesta al resto del código.

Tenga en cuenta que lo siguiente depende del conocimiento del dominio, así que lo mantendré abierto / sabrá cuál de estos tiene sentido / se aplica a las piezas que tiene. Yo diría que hay 3 opciones aquí:

  • ResourceMapper utiliza CachedResourceLoader, y usted solo expone el anterior al resto del código.
    • En este enfoque, hay un solo punto de entrada a través de ResourceMapper, por lo que tiene sentido que controle FreeUnused ().
    • Una vez que determina que puede liberar un recurso, lo eliminará del mapa. Si fuera necesario, llamaría a Unload para artículos específicos al CachedResourceLoader
  • Tanto CachedResourceLoader como ResourceMapper son utilizados por la persona que llama.
    • Si solo necesita FreeUnused de ResourceMapper, simplemente agréguela allí.
    • Si necesita ser liberado de ambos, uno de:
    • .FreeUnused en ResourceMapper recibe un CachedResourceLoader. Después de determinar / eliminar los elementos del mapa, pasa la lista de recursos para liberar a la instancia de cachedResourceLoader
    • .FreeUnused en ResourceMapper devuelve la lista de recursos liberados del mapa. La persona que llama llama .Unload en cachedResourceLoader pasando la lista de recursos para descargar. Quizás tengas un buen lugar en la persona que llama, estas dos llamadas encajarían bien.
  • Utiliza un ResourceManager, pero en lugar de tener todas las implementaciones allí, usa ResourceMapper y CachedResourceLoader. Sería muy delgado, simplemente haciendo llamadas a los demás, en particular las llamadas .FreeUnused y .Unload en el último subapartado anterior.

Una nota final: Creo que definitivamente vale la pena separar las responsabilidades y sentirse fuerte al hacerlo. Dicho esto, son los principios SÓLIDOS que más sigo, no memorizo ​​los nombres de los patrones y no le presto mucha atención a las reglas, como las clases de Gerente son malas.


10
2017-11-01 17:06



Ya casi lo dijiste:

Esta clase obtiene varias responsabilidades

(énfasis original).

Esto viola el Principio de Responsabilidad Individual. Además, la palabra Gerente sugerir un objeto que maneja otros objetos, lo cual está en desacuerdo con el principio orientado a objetos de que los objetos deben encapsular ambos datos y comportamiento. Esto lleva rápidamente a la Característica envidia código olor.

Dividir el administrador en muchas clases más pequeñas es lo correcto. Para mantenerlos manejables, puede implementar un Fachada sobre ellos.


13
2017-11-01 11:53



No necesita ser dogmático sobre los patrones de diseño o una arquitectura particular. Sólo hacer lo que tenga sentido y documentarlo bien.

En otras palabras, descomponer una clase en clases más pequeñas porque la clase más grande tiene múltiples responsabilidades es un buen principio, pero no un ley. No desea seguirlo a cualquier costo. Mire los pros y los contras de aplicarlo. A veces, descomponer una clase en clases más pequeñas le da más control sobre las responsabilidades, pero a expensas de una gran cantidad de comunicación entre esas clases. En su ejemplo, también podría implementar diferentes clases para la carga de recursos, almacenamiento en caché, mapeo, almacenamiento, etc. Pero si cada clase necesita hablar con los demás para realizar su trabajo, entonces la descomposición no vale la pena hacerlo, porque implica un alto acoplamiento, que es malo; mantener todo en una sola clase.

A veces pienso que los patrones de diseño han causado tanto daño como la claridad en el mundo del desarrollo de software. :-)


10
2017-11-01 19:43



No creo que algo esté necesariamente mal con tu solución. En mi humilde opinión si piensas en cosas que has dicho de Programación Orientada a Aspectosel punto de vista solo un aspecto de tus recursos será manejado por una clase.

Aunque si piensas en grande, tu base de código puede evolucionar en cientos de líneas, por lo que sería mejor desglosar tus funciones de infraestructura (Diseño impulsado por el dominio Patrones).

Creo que tu clase es coherente y el manager el nombre no siempre es una mala señal, excepto que consolida el flujo de control de muchas clases posiblemente no relacionadas que colaboran entre sí para realizar una tarea.

Si sus requisitos sobre el almacenamiento en caché y el mapeo son propensos a cambios, tal vez sería mejor Separa tus preocupaciones.

La regla empírica al tratar de escribir un código bien organizado es que al principio no lo tomes demasiado en serio, ten cuidado con los olores del código a medida que avanzas y refactoriza o refactoriza los patrones cuando sea necesario.


8
2017-11-01 17:40



Conozco todos estos patrones de diseño (Factory, Collection, Facade, etc.). Pero realmente no entiendo cómo se puede unir para crear un sistema de administración de recursos (fácil de administrar).

¿Quién dice que deberían unirse? Entonces estás de vuelta donde comenzaste, ¿verdad? Todo el punto en romper las clases de administrador es que terminas con múltiples componentes más simples. Si necesita la funcionalidad de almacenamiento en caché, hable con el caché. Si necesita la funcionalidad de carga de recursos, hable con el cargador de recursos.


4
2017-11-01 21:59