A Policy-Based Observer


Let's refactor that code.  While we're at it, let's now conform to the curent C++ Coding Standards, and not use names preceded with an underscore.

Let's fix issue 1. Sprinkle in std::list, for_each, bind2nd and mem_fun, and we're good to go. Now I can delete that custom container!

And let's fix issue 2. Templatize the message, so it can be push model, and Observers may subscribe to only the message types they want. (Or to as many different messages as they please.)

template < typename T >
class Observer {
public:
    virtual ~Observer() {};
    virtual void Update(T msg) = 0;
};

template < typename T >
class Subject {
public:
    virtual ~Subject() { observers_.clear(); };
    void Attach(Observer<T> *o) { observers_.push_back(o); };
    void Detach(Observer<T> *o) { observers_.remove(o); };
    void Notify(T msg) {
          std::for_each( observers_.begin(), 
              observers_.end(), 
              std::bind2nd(std::mem_fun( &Observer<T>::Update ), msg) );
          };
private:
    std::list <Observer<T> *> observers_;
};

That small refactor already buys us a lot of flexibility. Not to mention that it is both the declaration and definition of the classes, where we just had the declaration on the last page. Not bad! Using this pattern with one message type is trivial, and looks almost exactly like the original non-templatized code. So let's see what it looks like if we have objects that subscribe and publish more than one type of message. Let's see how some sample The Sims code might look:

class Sim : 
    public Observer<FoodMsg>, 
    public Observer<SocialMsg>
{
public:
    void Update(FoodMsg m);          // get it and eat, if we're hungry
    void Update(SocialMsg m);        // do I feel like visiting?
};

class Hottub :
    public Subject<FoodMsg>,   // wetbar
    public Subject<SocialMsg>  // friends/enemies
{
};

But now there's a new aesthetic problem: We have to fully-qualify the member functions when our Subjects publish multiple types, and that makes for ugly code.

    hottub->Subject<SocialMsg>::Attach(arline);       // Yuck!
    hottub->Subject<SocialMsg>::Notify(kWaterIsHot);  // Yuck!
Since we know that C++ compilers infer template parameters to template functions, we can slightly help out here by adding a couple of template functions.
template<class T>
void Attach(Subject<T> &subject, Observer<T> &observer)
{
    subject.Attach(&observer);
}

template<class T>
void Notify(Subject<T> &subject, T hint )
{
    subject.Notify(hint);
}
Let's see what our Attach and Notify functions look like now...
    Attach<SocialMsg>(hottub, arline);
    Notify<SocialMsg>(hottub, kWaterIsHot);

Not so much better, but stick with me. Those template functions are going to earn their keep when we try to figure out how to solve issue 3, the dangling pointers to observers.

We want our descendent classes to not care a whit about who gets deleted first. The Sim may die, or the Refrigerator may blow up. It shouldn't matter. We could add a list of the subjects that the observer has subscribed to, to the observer class. When the observer is destroyed, it could then inform the subjects that have pointers pointing to it.

That usage sounds a bit like the Observer pattern itself, but with the Observer informing the Subjects.

With this newfound flexibility, maybe we could put the onus of object tracking on the library's client? Why not make the Observer of message M also be a Subject with a list of all the Subjects it is observing? That way lies folly.