Al modelar un objeto con hijos, es común incluir a los hijos a través de la composición, como miembro de la clase padre. A veces, sin embargo, los niños necesitan decirle algo al padre, necesitan llamar a una función del padre. ¿Cómo se puede lograr esto usando C ++? Algunas opciones son:
Haga que la clase primaria sea global, por lo tanto, los objetos secundarios podrán llamar a las funciones miembro del objeto primario.
Inyecte el objeto primario como un puntero o referencia en cada objeto secundario. Luego, cuando el niño necesita decirle algo al objeto padre, siempre puede hacerlo porque tiene una variable miembro que puede usar.
¿Cuáles son otros métodos para hacer esto? ¿Existe un patrón o nombre de diseño general para este tipo de cosas?
Tenga en cuenta que estoy interesado en ideas y soluciones en C ++ porque los detalles serán diferentes en otros lenguajes orientados a objetos. Por ejemplo, el punto 2 anterior menciona 'punteros o referencias' y ambos solo son posibles en C ++. C ++ tiene características de lenguaje que no están presentes en otros idiomas, por lo tanto, las implementaciones de una solución al problema incorporarán potencialmente estas características de lenguaje, lo que hace que la solución sea diferente de lo que alguien podría encontrar en otro idioma.
delegate
suficiente un simple ?Respuestas:
Primero lo primero, esto puede ser un olor a código. El punto de usar la composición para los padres / hijos es que el padre sabe sobre los niños pero no al revés. Especialmente si la relación es más de un 'contiene' que 'está compuesto de'.
Una referencia al padre es posible y bastante común en C ++. En otros idiomas, un objeto o evento de función se usa con mayor frecuencia para permitir que el niño comunique cosas que personas externas pueden querer saber. Este es un tipo común de patrón de publicación-suscriptor. Sospecho que lo que es más idiomático depende de la versión de C ++ que esté usando y los estándares de su base de código.
fuente
Como otros han señalado, la idea básica de inyectar el objeto padre como puntero o referencia es el camino a seguir, en principio.
Esto tiene un inconveniente: obtienes una dependencia cíclica entre el padre y el hijo. Si desea evitar eso, defina una clase base abstracta (una interfaz)
IParent
de la que herede su padre.IParent
debe contener los métodos como funciones virtuales que el niño quiere llamar. Luego, inyecte el padre como referencia paraIParent
. Esto hace que las pruebas unitarias del niño sean mucho más fáciles, ya que ahora puede reemplazar fácilmente el objeto padre por un objeto simulado.Si su hijo necesita llamar solo a una función de su objeto padre, una
IParent
clase completa puede ser demasiado grande. En este caso, será suficiente para inyectar un puntero a la función miembro en el elemento secundario, o un objeto de función que encapsule esa función miembro.fuente
Lo que puede hacer es mantener una referencia al padre en la clase secundaria, por composición. De esa manera, el niño conoce a su padre y puede invocar métodos públicos en él.
Entonces, iría con la opción 2. Sin embargo, debe tener cuidado, cuando un niño se elimina del padre, debe eliminar la referencia al padre en el niño y señalarlo como nulo (o un nuevo padre, si tiene uno). O simplemente puede eliminar el objeto secundario, según el contexto.
fuente
Pásales una referencia o un puntero al padre. Puede hacerlos amigos del padre o hacer público el método llamado. Si no desea hacer nada de lo anterior, puede pasarles un objeto "puente" que exponga uno de los métodos del padre como público y que sea una clase privada anidada del padre (por lo tanto, tiene acceso a todos los métodos principales) ) Sin embargo, esto puede ser demasiado complejo en muchas situaciones.
fuente
Es una opción perfectamente viable. Todos los idiomas modernos tienen una función que puede usarse para referirse a otro idioma.
fuente
Existe un enfoque similar con una ligera variación, pero que ofrece ventajas:
Digamos que el padre A contiene el componente C.
En el Componente C, declare InterfaceC y mantenga la referencia a él. Esta es la interfaz del componente con el mundo exterior.
El padre A implementa InterfaceC, y establece su referencia en el componente C. El componente C ve al padre A como InterfaceC.
La idea es: un componente habla con el exterior usando su interfaz.
Las ventajas de usar esto sobre la configuración directa del padre son:
Digamos que el componente hace algo y necesita notificar a los padres. Llama a la interfaz. Más tarde, decide que desea cambiar el padre. Al componente no le importa en absoluto y no hará ningún cambio en él.
Di más tarde que quieres notificar a muchos objetos de un evento. Simplemente cree una lista de InterfaceC y agregue referencias a ella.
Desventajas: una clase principal terminará implementando muchas interfaces (creo que esto es una ventaja, ya que al mirar la declaración de la clase, inmediatamente sé quién habla con ella)
fuente
Tenga en cuenta que esto es específico de c #. No sé si C ++ tiene algo similar.
Si tiene una forma gui con botones pulsadores, generalmente tiene un enfoque diferente utilizando Event-Subscribtion, también conocido como Observer_pattern o Publish – subscribe pattern .
El botón usualmente no conoce la forma específica donde vive. En cambio, el botón activa o publica un evento y el formulario recibe una notificación suscrita y puede reaccionar en consecuencia.
Además de gui-s, este mecanismo se puede utilizar en todas las relaciones paren-niño
fuente