Estoy trabajando en un pequeño juego escrito en Java (pero la pregunta es independiente del idioma). Como quería explorar varios patrones de diseño, me colgué en el sistema Composite pattern/Entity (que originalmente leí sobre here y here) como una alternativa a la típica herencia jerárquica profunda.El sistema de patrón/entidad compuesto y OOP tradicional
Ahora, después de escribir varios miles de líneas de código, estoy un poco confundido. Creo que entiendo el patrón y me gusta usarlo. Creo que es genial y Starbucks-ish, pero parece que el beneficio que proporciona es de corta duración y (lo que más me molesta) depende en gran medida de su granularidad.
Aquí tenemos una imagen del segundo artículo anterior:
Me encanta la forma de objetos (entidades de juego, o como quieran llamarlos) tienen un conjunto mínimo de componentes y la idea inferida es que se puede escribir código que se ve algo como:
BaseEntity Alien = new BaseEntity();
BaseEntity Player = new BaseEntity();
Alien.addComponent(new Position(), new Movement(), new Render(), new Script(), new Target());
Player.addComponent(new Position(), new Movement(), new Render(), new Script(), new Physics());
.. que sería muy agradable ... pero en realidad, el código termina buscando algo así como
BaseEntity Alien = new BaseEntity();
BaseEntity Player = new BaseEntity();
Alien.addComponent(new Position(), new AlienAIMovement(), new RenderAlien(), new ScriptAlien(), new Target());
Player.addComponent(new Position(), new KeyboardInputMovement(), new RenderPlayer(), new ScriptPlayer(), new PhysicsPlayer());
Parece que termino teniendo algunos componentes muy especializados que se componen de componentes menores. Muchas veces, tengo que hacer algunos componentes que tienen dependencias de otros componentes. Después de todo, ¿cómo puedes renderizar si no tienes una posición? No solo eso, sino la forma en que terminas representando un jugador contra un extraterrestre vs. una granada puede ser fundamentalmente diferente. No puede tener UN componente que dicte los tres, a menos que haga un componente muy grande (en cuyo caso ... ¿por qué está usando el patrón compuesto de todos modos?)
Para dar otro ejemplo de la vida real. Tengo personajes en mi juego que pueden equipar varios equipos. Cuando se equipa una pieza de equipo, se cambian algunas estadísticas y se muestran visualmente. Esto es lo que mi código es el momento:
billy.addControllers(new Movement(), new Position(), new CharacterAnimationRender(), new KeyboardCharacterInput());
billy.get(CharacterAnimationRender.class).setBody(BODY.NORMAL_BODY);
billy.get(CharacterAnimationRender.class).setFace(FACE.BLUSH_FACE);
billy.get(CharacterAnimationRender.class).setHair(HAIR.RED_HAIR);
billy.get(CharacterAnimationRender.class).setDress(DRESS.DRAGON_PLATE_ARMOR);
Lo anterior CharacterAnimationRender.class
sólo afecta a lo que se muestra visual. Entonces claramente necesito hacer otro Componente que maneje las estadísticas de los cambios. Sin embargo, ¿por qué debería hacer algo como:
billy.addControllers(new CharacterStatistics());
billy.get(CharacterAnimationRender.class).setBody(BODY.NORMAL_BODY);
billy.get(CharacterStatistics.class).setBodyStats(BODY_STATS.NORMAL_BODY);
Cuando sólo puedo hacer una CharacterGearStuff
controlador/componente que maneja tanto la distribución de las estadísticas, así como el cambio visual?
En pocas palabras, no estoy seguro de cómo se supone que esto ayuda a la productividad, ya que a menos que desee manejar todo manualmente, aún debe crear "metacomponentes" que dependan de más de 2 componentes (y modificar/cruzar modificar todos sus subcomponentes, devolviéndonos a OOP). O tal vez estoy pensando en eso completamente mal. ¿Soy yo?
Hola Adam, gracias por responder a esta pregunta: D - He dividido adecuadamente los datos y la lógica de mi código (como mencionas en tu blog, en realidad). De hecho, 'Position()', 'Movement()', etc. son lo que yo llamo controladores que "dependen" de modelos de datos (que podríamos llamar componentes, supongo, que son clases simples que forman parte de SÓLO privadas miembros de datos (en el caso de posición, 'private double x;' y 'private double y;') - hago todo este enlace internamente a los controladores. –