He encontrado un problema interesante al implementar el patrón Observer con C++ y STL. Considere este ejemplo clásico:Problemas al implementar el patrón "Observer"
class Observer {
public:
virtual void notify() = 0;
};
class Subject {
public:
void addObserver(Observer*);
void remObserver(Observer*);
private:
void notifyAll();
};
void Subject::notifyAll() {
for (all registered observers) { observer->notify(); }
}
Este ejemplo se puede encontrar en todos los libros sobre patrones de diseño. Desafortunadamente, los sistemas de la vida real son más complejos, así que este es el primer problema: algunos observadores deciden agregar otros observadores al Sujeto al ser notificados. Esto invalida el ciclo "for" y todos los iteradores que uso. La solución es bastante fácil: hago una instantánea de la lista de observadores registrados e itero sobre la instantánea. Agregar nuevos observadores no invalida la instantánea, por lo que todo parece estar bien. Pero aquí viene otro problema: los observadores deciden destruirse a sí mismos al ser notificados. Peor aún, un solo observador puede decidir destruir a todos los demás observadores (están controlados a partir de los scripts) y eso invalida tanto la cola como una instantánea. Me encuentro iterando sobre punteros desasignados.
Mi pregunta es ¿cómo debo manejar las situaciones, cuando los observadores se matan entre sí? ¿Hay algún patrón listo para usar? Siempre pensé que "Observer" es el patrón de diseño más fácil del mundo, pero ahora parece que no es tan fácil implementarlo correctamente ...
Gracias a todos por su interés. Tengamos un resumen de las decisiones:
[1] "No lo hagas" Lo sentimos, pero es obligatorio. Los observadores se controlan desde los scripts y son recolectados. No puedo controlar la recolección de basura para evitar su desasignación;
[2] "Use boost :: signal" La decisión más prometedora, pero no puedo introducir impulso en el proyecto, tales decisiones deben tomarlas únicamente el líder del proyecto (estamos escribiendo bajo Playstation);
[3] "Usar shared__ptr" Eso evitará que los observadores se desasignen. Algunos subsistemas pueden confiar en la limpieza del grupo de memoria, por lo que no creo que pueda usar shared_ptr.
[4] "Posponer la desasignación de observador" Poner en cola los observadores para su eliminación mientras notifica, luego use el segundo ciclo para eliminarlos. Desafortunadamente, no puedo evitar la desasignación, así que utilizo un truco para envolver al observador con algún tipo de "adaptador", manteniendo en realidad la lista de "adaptadores". En destructor, los observadores eliminan la asignación de sus adaptadores, luego tomo mi segundo ciclo para destruir los adaptadores vacíos.
p.s. ¿Está bien, que edite mi pregunta para resumir toda la publicación? Soy novato en StackOverflow ...
¡Buena pregunta! No había considerado usar el patrón de observadores donde los observadores pueden crear y destruir otros observadores del sujeto. –
Me gusta resumir las respuestas de la pregunta en la pregunta, simplemente no altere la pregunta original con eliminaciones o lectores posteriores pueden perderse los matices de la pregunta original (no es que lo haya hecho, creo que su resumen y señalar que su resumen es excelente) – Jay
¿Alguna vez ha probado alguno de estos para ver cuál le gustó más o si se sintió mejor? – prolink007