Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Observer pattern in C++ [closed]

I have one Animation class. I need to have some observers for Play, Pause and Stop events in the Animation. I found 2 solutions for this problem, but I dont't know what to chose.

  1. Use boost::signals or something similar and register callbacks for every event

  2. Make a simple interface with 3 pure virtual functions(OnPlay(), OnPause(), OnStop()) and pass to the Animation class objects that implement this interface.

There are advantages and disadvantages for every method. I'll try to enumerate the ones that I found so far:

Advantages for 1.

  • I can use any member function/free function as a callback
  • I don't have to implement all 3 functions if I don't care about all of them
  • Same object can be used as observer for multiple animations without passing extra parameters from Animation class

Disadvantages for 1.

  • I have to create a callable object for every callback
  • If I want to add later a new event it will be hard to find the places where it was used(compiler can't enforce me to implement or ignore new event).
  • Somehow weird syntax(I have to use std::bind/boost::bind everywhere).

Advantages for 2.

  • Easy to understand construction
  • If I'll add a new event in Animation/Observer interface class the compiler will enforce me to implement(empty maybe) the new function.

Disadvantages for 2.

  • I have to implement (empty maybe) 3 functions even if I'll use only one
  • Same object can't be used as observer for different animation without sending some extra parameter from animation(ID or something).
  • Free functions can't be used.

Can you please advise me what to use? From your experience what is better for this problem - the freedom from first aproach or clear and easy to understand code from the second one? Can you please give me other advantages/disadvantages for both methods or other solution?

like image 515
Mircea Ispas Avatar asked Jul 29 '13 12:07

Mircea Ispas


2 Answers

First of all, it would be useful to know if the "binding" is known at compile-time or not. If so, I would suggest you to look into policy classes.

Apart from that, I would go for a mix of the two solutions, i.e. use the interface approach and implement one interface which acts as a relayer for signals/free-functions. This way you can have default behaviours, you can add custom objects implementing the whole interface and have, basically, the advantages of the two approaches as well as much flexibility.

Here is a basic example of the proposed approach, I hope it is of help.

#include <functional>

using namespace std;

template <class ObserverPolicy>
class Animation : public ObserverPolicy{

};

class MonolithicObserver{
    public:
    void play(){
        state = playing;
    }
    void pause(){
        if(playing == state)
            state = stopped;
    }
    void stop(){
        state = stopped;
    }
    private:
    enum {playing, paused, stopped} state;
};

struct doNothing{
    static void play(){}
    static void pause(){}
    static void stop(){}
};

struct throwException{
    class noPlay{};
    class noPause{};
    class noStop{};
    static void play(){
        throw noPlay();
    }
    static void pause(){
        throw noPause();
    }
    static void stop(){
        throw noStop();
    }
};

template <class DefaultPolicy = doNothing>
class FreeFunctionObserver{
    public:
    void play(){
        if(playHandle)
            playHandle();
        else
            DefaultPolicy::play();
    }
    void pause(){
        if(pauseHandle)
            pauseHandle();
        else
            DefaultPolicy::pause();
    }
    void stop(){
        if(stopHandle)
            stopHandle();
        else
            DefaultPolicy::stop();
    }
    void setPlayHandle(std::function<void(void)> p){
        playHandle = p;
    }
    void setPauseHandle(std::function<void(void)> p){
        pauseHandle = p;
    }
    void setStopHandle(std::function<void(void)> p){
        stopHandle = p;
    }
    private:
    std::function<void(void)> playHandle;
    std::function<void(void)> pauseHandle;
    std::function<void(void)> stopHandle;
};

void play(){}
void pause(){}
void stop(){}

int main(){
    Animation<FreeFunctionObserver<> > affo;
    affo.setPlayHandle(play);
    affo.setPauseHandle(pause);
    affo.setStopHandle(stop);
    affo.play();
    affo.pause();
    affo.stop();

    Animation<FreeFunctionObserver<throwException> > affot;
    try{
        affot.play();
    }
    catch(throwException::noPlay&){}

    Animation<MonolithicObserver> amo;
    amo.play();
    amo.pause();
    amo.stop();
}

which you can try here. This example, in particular, uses a policy class (hence no interface is "formally" defined, and you can "enrich" the interface, as done with setPlayHandle). However, you can do something similar with run-time binding too.

like image 162
Stefano Falasca Avatar answered Oct 03 '22 14:10

Stefano Falasca


For all but the simplest of toy examples, Boost.Signals2 would be the superior solution in my opinion. It is well-designed, well-tested and well-documented. Reinventing the wheel is nice for homework type of exercises, but not for production code. E.g. making your own observer thread-safe is non-trivial to get right and efficient.

Specifically discussing your listed disadvantages

  • you can write C++11 lambdas instead of named function objects or using boost::bind syntax (which is not really complicated for most usage anyway)
  • I don't quite understand your point about unused events. You can do quite advanced connnection management to query and disconnect signals from slots.

TL;DR: familiarize yourself with Boost.Signals2

like image 20
TemplateRex Avatar answered Oct 03 '22 14:10

TemplateRex