Observer Pattern

 

Hello everyone,


i'm tryng to implement the Observer Pattern as described here (https://www.tutorialspoint.com/design_pattern/observer_pattern.htm) but i'm failing really hard.

This is what i coded

#include <Object.mqh>
#include "Subject.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObserver : public CObject
  {
protected:
   Subject           subject;

public:

                     CObserver();
                    ~CObserver();

   void             ObserverUpdate() {};
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CObserver::CObserver()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CObserver::~CObserver()
  {
  }
//+------------------------------------------------------------------+
#include "Observer.mqh"
#include <Arrays/List.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSubject
  {
private:

   CList            *Observer;
   int               State;

public:
                     CSubject();
                    ~CSubject();

   int GetState() {return State;}
   void SetState(int state) {State=state; NotifyAllObserver();}

   void              NotifyAllObserver();

  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSubject::CSubject()
  {
   Observer=new CList();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSubject::~CSubject()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSubject::NotifyAllObserver(void)
  {
   for(int i=0; i<Observer.Total(); i++)
     {
      //Observer.ObserverUpdate();
     }
  }
//+------------------------------------------------------------------+

I get this error:

1- 'Subject' - declaration without type, Observer.mqh, 16 4

2- 'ObserverUpdate' - member function not defined, Subject.mqh, 51 16


First error i really don't understand why, the second i think i need a way to declare a list of observer type, what is the solution here? 


Thanks


Design Patterns Observer Pattern
Design Patterns Observer Pattern
  • tutorialspoint.com
  • www.tutorialspoint.com
Design Patterns Observer Patterns - Learning java design patterns in simple and easy steps : A beginner's tutorial containing complete knowledge about an java design patterns starting from its Factory Pattern, Abstract Factory, Singleton, Builder, Prototype, Adapter, Bridge, Filter, Composite, Decorator, Facade, Flyweight, Proxy, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Null Object,Strategy, Template, Visitor, MVC, Front Controller etc.
 
d.bignotti:
1- 'Subject' - declaration without type, Observer.mqh, 16 4

2- 'ObserverUpdate' - member function not defined, Subject.mqh, 51 16

  1. protected:
       Subject           subject;
    You never define a Subject. You defined a
    class CSubject{
  2. for(int i=0; i<Observer.Total(); i++){
       //Observer.ObserverUpdate();
      }
    • Observer is a CList and that doesn't have any such method called ObserverUpdate.
    • You store subject pointers in the list as CObject pointers (code TBD.) You have to fetch them, one by one, cast them back to a subject and then tell the subject about the update.
    • Why did you make it a pointer? You forgot to delete it in the destructor. Why not just include it in the class?
 
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
class Observer; //forward declarations
class Subject;
//+------------------------------------------------------------------+
class ObserverList : public CArrayObj
{
   public: Observer* operator[](int i){return At(i);}
};
//+------------------------------------------------------------------+
class Observer : public CObject
{
protected:
   Subject    *m_subject;
public:
   virtual void update()=0;
};
//+------------------------------------------------------------------+
class OctalObserver : public Observer
{
public: 
   OctalObserver(Subject *subject)
   {
      m_subject = subject;
      m_subject.attach(&this);
   }   
   virtual void update() override
   {
     printf( "Octal String: %d",m_subject.getState()); 
   }
};

//+------------------------------------------------------------------+
class Subject : public CObject
{
   int            m_state;
   ObserverList   m_observers;
public:
   Subject(){}
   int getState() {
      return m_state;
   }

   void setState(int state) {
      m_state = state;
      notifyAllObservers();
   }

   void attach(Observer *observer){
      m_observers.Add(observer);                
   }

   void notifyAllObservers(){
      for (int i=0;i<m_observers.Total();i++) {
         m_observers[i].update();
      }
   }    
};
//+------------------------------------------------------------------+
 

whroeder1:


...............


nicholishen:

...........

Thanks whroeder1 for the fantastic insight.

Thanks nicholishen for the entire solution, i know the logic behind it now.

 
nicholishen:

I'm applying nicholsen solution and it works well, but i see there's new data collection generic called ArrayList or LinkedList in include/Generic folder.

I'm trying to use it instead of CArrayObject, but i can't understand how to access list element throught index only.

Can anyone help here?

   CArrayList<CCar*>car;

   CCar *yama=new CCar("yamaha");

   car.Add(new CCar("honda"));
   car.Add(new CCar("zama"));
   car.Add(new CCar("ferrari"));
   car.Add(new CCar("mercedes"));
   car.Add(new CCar("audi"));
   car.Add(new CCar("pegueot"));
   car.Add(yama);

   for(int i=0; i<car.Count(); i++)
     {
     //how to iterate throught all the list and access the CCar methods?
     }
class CCar
  {
private:
   string            nome;
public:
                     CCar(string questonome);
                    ~CCar();
                    string getNome() {return nome;}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CCar::CCar(string questonome)
  {
   nome=questonome;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CCar::~CCar()
  {
  }
//+------------------------------------------------------------------+
 
d.bignotti: I'm trying to use it instead of CArrayObject, but i can't understand how to access list element throught index only.
  1. There is no such thing as CArrayObject

  2. You look at the Arrays\ArrayObj.mqh
    class CArrayObj : public CArray{
    protected:
       CObject          *m_data[];           // data array
    It only stores pointers to CObject, therefor your class must derive from that.

  3. There is:
       //--- method of access to thre array
       CObject          *At(const int index) const;
    
    Thus get the object pointer, cast it to your class and use it.
       CArrayObj car;
       car.Add(new CCar("honda"));
       :
    
       for(int i=0; i<car.Count(); i++)
         {
         CCar* t = (CCar*)car.at(i); 
         Print(t.getNome() );
         }
 
whroeder1:
  1. There is no such thing as CArrayObject

  2. You look at the Arrays\ArrayObj.mqhIt only stores pointers to CObject, therefor your class must derive from that.

  3. There is:Thus get the object pointer, cast it to your class and use it.

You are right, the correct name is CArrayObj, i'm using it already and i understand how it works, i see there's a new colelction called CArrayList  in include/Generic folder.

Do you have any experience with that? 

I can't find a way to access CArrayList object throught index like in CArrayObj.

 

What part of these methods are unclear?

   //--- methods for navigating
   int               IndexOf(CObject *node);
   CObject          *GetNodeAtIndex(int index);
   CObject          *GetFirstNode(void);
   CObject          *GetPrevNode(void);
   CObject          *GetCurrentNode(void);
   CObject          *GetNextNode(void);
   CObject          *GetLastNode(void);
 
whroeder1:

What part of these methods are unclear?


What part of CArrayList is unclear?


I can't find a way to access CArrayList object throught index like in CArrayObj.

See the docs at the link I posted above.


Also note: The Generic collection classes don't implement CObject so you won't be able to use the CObject virtual methods such as Compare for sorting, Load, Save, etc. I would recommend sticking with a collection that implements CObject such as CArrayObj, CList, or CDictionary.

 
This implimentation of observer is useless without multi inheritance.

 
Amir Yacoby:
This implimentation of observer is useless without multi inheritance.


I'v posted a new topic on this argument in this section of the forum 30 min before your comment.

Reason: