Let's try out the idea of making an idiom for the users of our pattern. Their observers must also be subjects that send out "detach me" notices when they are deleted. And their subjects will be observers of those messages Like so:
Let's try out the idea of making an idiom for the users of our pattern. Their observers must also be subjects that send out "detach me" notices when they are deleted. And their subjects will be observers of those messages Like so:
class Sim : public Observer<FoodMsg>, public Subject<Observer<FoodMsg> *> // Notify() to detach me when I go. { public: Sim() {}; ~Sim() { Subject<Observer<FoodMsg> *>::Notify(this); } void Update(FoodMsg m); }; class Hottub : public Subject<FoodMsg>, public Observer<Observer<FoodMsg> *> // Detach from those who nofify me. { public: Hottub() {}; void Update(Observer<FoodMsg> *p) { Subject<FoodMsg>::Detach(p); } };
Awesome! This works! Now observers can be deleted before subjects!
But, wait. Now that observers contain a list of subjects, when one of those subjects leaves early, it'll have to notify the observer that's watching it to notify it of its demise.
OK, let's make the observer be an observer of type subject of message, and when it gets a message that the subject is going, it'll remove it from its list of subjects.
class Sim : public Observer<FoodMsg>, public Observer<Subject<FoodMsg> *>, public Subject<Observer<FoodMsg> *> { public: ~Sim() { Subject<Observer<FoodMsg> *>::Notify(this); } void Update(FoodMsg m); void Update(Subject<FoodMsg> *p) { Detach((Observer<Observer<FoodMsg> *> *) p); } }; class Hottub : public Subject<FoodMsg>, public Subject<Subject<FoodMsg> *>, public Observer<Observer<FoodMsg> *> { public: ~Hottub() { Subject<Subject<FoodMsg> *>::Notify(this); }; void Update(Observer<FoodMsg> *p); };
Umm. OK. But now when Hottub gets the message that it needs to detach the Sim, it'll have to know that it has to detach the Sim from both base classes' lists. Oh, and we'll have to ask our library clients to remember to Attach each class to the other class's lists.
... // Attach for the message type, and // attach for the pointer to subject, and // attach for the pointer to observer. hottub->Subject<FoodMsg>::Attach(arline); hottub->Subject<Subject<FoodMsg> *>::Attach(arline); arline->Attach(hottub); ... void Hottub::Update(Observer<FoodMsg> *p) { // We want to delete p from both lists. // Runtime Bug: p shouldn't be the same when // pointing to either of its base classes. // And here we have no way of knowing what to do. Subject<FoodMsg>::Detach(p); Subject<Subject<FoodMsg> *>::Detach((Observer<Subject<FoodMsg> *> *) p); }
A bug! Thank God! There was no way we could ask our library clients to use an awful idiom like this anyway. What a stupid idea. Let's go put the object tracking code in a policy in the base classes where it belongs. C'mon, let's get out of here.