Search code examples
javac++objective-cdesign-patternsobserver-pattern

Implement Observer Pattern in C++


The observer pattern can be really useful in event-driven systems. Here's how it might be implemented in two languages:

Java

Use an AOP library or byte-code engineering (BCEL, cglib, asm, etc) to create a sub-class on the fly. Any calls to the getter or setter of an observed property notifies any attached observers.

Objective-C

This is similar to Java - uses isa swizzling to create a sub-class on the fly. Any calls to an observed property notifies attached observers. Interestingly, in Objective-C we can swizzle back to the original class without the wrapped property methods, if all observers are removed. Whereas in Java a class is typically loaded once, so you're always notifying a (possibly empty) set of observers.

How about C++?

With limited reflection in C++, it would be difficult to use the above approaches. What is the "best" (by that I mean typical or defacto-standard) approach in C++? Is there any way to avoid the boiler-plate code like in the Java and Objective-C implementations that I referenced above? Perhaps using C++ meta-programming features?


Solution

  • I don't believe there is a way to implement the Observer pattern in C++ using just reflection. If you don't use any external tools, you have to implement everything manually. For instance, I'd implement it something like:

    #include <iostream>
    #include <set>
    using namespace std;
    
    class Impl;
    
    class ObserverBase {
    public:
        virtual void propertyChanged(Impl *impl, int value) = 0;
    };
    
    class Impl {
    public:
        void setProperty(int value) {
            if (m_property != value) {
                m_property = value;
                for(auto observer:m_observers) {
                    observer->propertyChanged(this, value);
                }
            }
        }
        int getProperty() {
            return m_property;
        }
    
        void addObserver(ObserverBase *observer) {
            m_observers.insert(observer);
        }
    private:
        int m_property;
        set<ObserverBase *> m_observers;
    };
    
    class Observer : public ObserverBase {
    public:
        virtual void propertyChanged(Impl *impl, int value) {
            cout << "Saw new value of " << value << "!" << endl;
        }
    };
    
    int main() {
        Impl impl;
        impl.addObserver(new Observer());
        impl.setProperty(5);
    }
    

    If you want ObserverBase and the for loop in Impl to be auto-generated, you could parse the C++ at compile time. I don't know of anything that does that for you.

    If you are using a third-party library, they may include tools to help. For instance, if you are using Qt, you could use signal/slots to notify observers of changes.