0 Background

   Observer, I think every programer is too familiar with this name, even when we are still in campus. If just open any of open source projects, so many observer patterns would make feel tricky, and make the code not straight forward enough about the implementation at the first sight.

    Yes, you are right, I hate this pattern at the very beginning. So many files need to be added into the project even if I only want to go through one really simple operation scenario and all  the function call stack to figoure out what is done here. It is so completed with IDE to review the code, so I can hardly imagine if only vim/Emacs/web without plug-ins. You would never know what is done in the observer before this programme is running and all the observers has its instance. To tell you the truth, in my mind our archtecture’s ass are kicked so many times due to this wonderful design which I realized finally.

    As I mentioned in last article, design pattern would never help about any implementaion, or satify your customer with great idea, or even ensure your code execute a little smoothly.  This is still the rule for observer. Design pattern could only help about the code architecture, devide some of the components seperated from others and to some extend, easy to extend and easy to understand. I know, everyone has questions about the last benifit, but if we can review the code from ‘Object Oriented”s point of view instead of the ‘Processing Oriented’ one, in fact, it helps a lot to understand each component’s job. I think this is the key of observer pattern or some design patterns else, which is, cares what every object(class) can support, not every scenario/process could be executed.

1 What is Observer Pattern

    Let’s refer to wiki as usual,

    https://en.wikipedia.org/wiki/Observer_pattern.    –

    ‘The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems. The Observer pattern is also a key part in the familiar model–view–controller (MVC) architectural pattern

    What’s the ****? What I can get is only one terrible information – ‘a list of…’ – OMG, a list of?  I have big problem of understanding this pattern, but wiki is telling me that, don’t worry, it takes two, so does the problem. Oh, not two, it is a ‘list’….

    Forget about the list, MVC or something else, let’s start from the very beginning. One operation, One observer.

    Also, before the code, my environment is

Linux version 3.17.7-200.fc20.x86_64 (gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC) )

Supposing there is an operation class named ‘NOperationA’ which has the function of ‘Execute’ to deal with some tasks we need and here is the implementation. (Here is only part of the code, not the buildable ones before we finish)

// NOperationA.cpp

#include “NOperationA.h"

NOperationA::NOperationA(IOperationObserver* observer):
Name("Opeartion A"),
{
// empty
}

void NOperationA::Execute()
{
OPTRACE("[%s] Start Executing...", Name.c_str());
// Execute scenario..
//

OPTRACE("[%s] Execute Completed.", Name.c_str());

return;
}

And assume there is something else need to be done immediately after the this the operation is executed. How will we implement this without this observer pattern?


void NOperationA::Execute()
{
OPTRACE("[%s] Start Executing...", Name.c_str());
// Execute scenario..
//

OPTRACE("[%s] Execute Completed.", Name.c_str());

// Something after executing
// ...

OPTRACE("Something after executing completed.");
return;
}

Yes, it seems that everything is OK. Now what we need to do is to separate them and make the whole thing ‘Object oriented’.  Before that, we have to make it clear that what is ‘something after executing completed’?

For example, I have just commented your new post on facebook about your your football battle last weekend, ‘Wonderful game!’ , and then I press the enter. ‘NOperationA’ is responsible for the sending the comment to server. Encoding text, package, establish the connection, putting data on it, waiting for server response… should be in ‘Execute’. Then, ‘something after executing completed’? Just some update in the UI on my application, like web/some native application on my device, like message box’Comment success’, post flush with my comment or something else.

Obviously, this ‘something after executing completed’ is of course not in the scope of this ‘NOperationA’. The ‘Execute’ terminated after get the response from server. The scenario is over, rest of work should be completed in the UI manager or something else, definitely not in this ‘OperationA’. Different UI may has its own ‘something after executing’, and maybe change in a high frequency according to requirement. It has so much benefit to separate them, here comes the ‘Observer’.

If we can push all these ‘something after executing’ into ‘NOperationA”s observer, like this

// NOperationA.cpp

#include "NOperationA.h"

NOperationA::NOperationA(IOperationObserver* observer):
Name("Opeartion A"),
Observer(observer)
{
// empty
}

void NOperationA::Execute()
{
OPTRACE("[%s] Start Executing...", Name.c_str());
// Execute scenario..
//

OPTRACE("[%s] Execute Completed.", Name.c_str());

Observer->OnOperationCompleted(Name);
return;
}

Here, in this ‘NOperationA’ we has a member ‘Observer’, which is a point intialized when constructed, or somewhere else, which does not matter and is OK before ‘Execute’. In the end of ‘Execute’, ‘OnOperationCompleted’ of ‘Observer’ is called, which means, this ‘NOperationA’ tells the oberser ‘Hey, all my stuff has been done, the next is your part’ and then the process/scenario would be completed with every individual components.

2 Interface Defination

Obvisously, ‘NOperationA’ would never know what would be his observer until it constructs or his observer is passed in. And from the its observer point of view, any object could be its observer as long as it implements the callback ‘OnOperationCompeleted(std::string)’. This Observer member would be real instance only in run-time.  So here, what we need is only a ‘Operation Observer’ interface and a pure virtual function ‘OnOperationCompleted(std::string)’ defined for ‘NOperationA’ to declare the observer. When there is some ‘real observers’, what they need to do is only inherit this observer interface and implement the function. As there would be some other’s sake which is not in the scope in this article, we define the operation interface itself along with this ‘observer interface’ without explanation as below,

// IOperation.h

#ifndef _I_OPERATION_
#define _I_OPERATION_
#include <string>

#include <stdio.h>
#define OPTRACE(fmt, args...)      printf("[Operation]\t" fmt "\n", ## args)
#define OBTRACE(fmt, args...)      printf("[Observer ]\t" fmt "\n", ## args)
class IOperationObserver
{
public:
virtual ~IOperationObserver() {};
virtual void OnOperationCompleted(std::string operationName) = 0;
};

class IOperation
{
public:
virtual ~IOperation() {};
virtual void Execute() = 0;
};

#endif
#endif 
3 Implementation

Here we have interface ‘IOperationObserver’ and ‘IOperation’ defined, so the rest is more clear and easier. Any operation class only need to inherit ‘IOperation’ while any observer of ‘IOperation’ just need to inherit ‘IOperationObserver’.

Here is the definition and implementation of ‘NOperationA’ and ‘NObserverA’.

// NOperationA.h

#ifndef _N_OPERATION_A_H_
#define _N_OPERATION_A_H_
#include "IOperation.h";

class NOperationA: public IOperation
{
public:
NOperationA(IOperationObserver* observer);
virtual void Execute();
private:
std::string Name;
IOperationObserver* Observer;
};
#endif

 

// NOperationA.cpp

#include "NOperationA.h"

NOperationA::NOperationA(IOperationObserver* observer):
    Name("Opeartion A"),
    Observer(observer)
{
    // empty
}

void NOperationA::Execute()
{
    OPTRACE("[%s] Start Executing...", Name.c_str());

    // Execute scenario..
    //

    OPTRACE("[%s] Execute Completed.", Name.c_str());

    Observer->OnOperationCompleted(Name);
    return;
}
// NObserserA.h

#ifndef _N_OBSERVER_A_H_
#define _N_OBSERVER_A_H_
#include "IOperation.h";
class NObserverA: public IOperationObserver
{
public:
    NObserverA();
    virtual void OnOperationCompleted(std::string operationName);
private:
    std::string Name;
};
#endif

 

// NObserverA.cpp

#include "NObserverA.h";
NObserverA::NObserverA():
    Name(Observer A)
{
    // empty
}

void NObserverA::OnOperationCompleted(std::string operationName)
{
    OBTRACE("[%s] end working...", operationName.c_str());
    OBTRACE("[%s] callback start working...", Name.c_str());

    // Callback scenario

    OBTRACE("[%s] callback compeleted.", Name.c_str());
    return;
}

At last we have a simple main and makefile to try this design,

// main.cpp
#include "NObserverA.h";
#include "NOperationA.h";

int main()
{
    IOperationObserver* observer;
    IOperation* operation;

    observer = new NObserverA();
    operation = new NOperationA(observer);

    operation->Execute();

    delete operation;
    delete observer;
    return 0;
}

 

### Requires

### Targets
SRC += *.cpp
TARGET += TinyObserver

##Build
edit: $(SRC)
g++ $(SRC) -o $(TARGET)

At last, we get the output as below,

[Operation]    [Opeartion A] Start Executing...
[Operation]    [Opeartion A] Execute Completed.
[Observer ]    [Opeartion A] end working...
[Observer ]    [Observer A] callback start working...
[Observer ]    [Observer A] callback compeleted.

Everything is what we expected.

4 Extension
Now, we have figure out what/why there is an observer, and how to design/implement it. But as we all know, this is a ‘tiny’ observer because there is only one observer designed/implemented for ‘NOperationA’, how could be a ‘list’ as wikipedia said?

I think it is not a issue because we have the ‘observer’ work through one member named ‘Observer’. If there is requirement that it has more than one ‘observer’, just update to the ‘IObserver*’ to list/vector/map or something else like ‘std::list<IObserver*>’ etc… Define another ‘AddObserver’, ‘RemoveObserver’, ‘NotifyAll’ or some other functions instead of initial the member in the constructor. As here we only talk about the simplest case, the ‘tiny’ one, so no more code would be post out. I think it is quite implementable, everyone could try to extend it and verify.

Advertisements