0

I have been giving the following problem to solve. Make a generic Subject class (referring to Observor Pattern) such that it can accept any data type( primitive or user type). The register, remove and notify functions are also required to be customizable. As an example, we have a WeatherStation class which notifies observors on data type 'int'. It makes a DB entry on registering and removing observors.

Another example(not shown) is BroadcastHandler which notifies observors on stock exchange quotes. It makes entry in files on registering and removing observors.

I wrote the following code to implement it.

#include <iostream>
#include <set>

template <class T>
class Observor
{
  public :
  virtual void update(const T& t) = 0;
  virtual ~Observor(){}
};

template<class T>
class Subject
{
  public :
  virtual void registerObservor(Observor<T>* obv) = 0;
  virtual void removeObservor(Observor<T>* obv) = 0;
  virtual void notifyObservors(T t);
  virtual ~Subject(){}
};

template<class T>
class WeatherStation : public Subject<T>
{
  public :
  void registerObservor(Observor<T>* obv)
  {
    _observors.insert(obv);
    //Make DB Entry
  }

  void removeObservor(Observor<T>* obv)
  {
    if(_observors.find(obv) != _observors.end())
    {
        _observors.erase(obv);
        //Make DB Entry
    }
  }

  void notifyObservors(T t)
  {
    for(auto itr = _observors.begin(),
    itrEnd = _observors.end(); itr != itrEnd; ++itr)
    {
        (*itr)->update(t);
    }
  }

private :
std::set< Observor<T>* > _observors;
};

int main()
{
  WeatherStation<int> wStation;
}

I get the following error from the linker

observor_pattern.o:observor_pattern.cpp:(.rdata$_ZTV7SubjectIiE[__ZTV7SubjectIiE]+0x10)||undefined reference to `Subject<int>::notifyObservors(int)'
Pranav Kapoor
  • 1,171
  • 3
  • 13
  • 32
  • Is all this code in one file? – Petr Jul 07 '15 at 17:13
  • On purpose for now, I will shift the subject and observor base classes to another file once I have working code – Pranav Kapoor Jul 07 '15 at 17:14
  • I've just thought initialy that you might have forgotten that template implementation must be included into header, but now I see another reason for the linker error, see my answer. – Petr Jul 07 '15 at 17:18

1 Answers1

0

Indeed (as the linker tells you) you do not have definition of Subject<T>::notifyObservors(T), and you did not declare it as =0. Was this intentional? I think a proper code might be

template<class T>
class Subject
{
  public :
  virtual void registerObservor(Observor<T>* obv) = 0;
  virtual void removeObservor(Observor<T>* obv) = 0;
  virtual void notifyObservors(T t) = 0;
                               //   ^^^
  virtual ~Subject(){}
};

Though even a better approach would be to have all observor-handling code in Subject, not in WeatherStation, because that seems to be what Subject class is all about. It's Subject's responsibility to handle Observors, and WeatherStation's responsibility should be to get data from sensors, etc.

Petr
  • 9,812
  • 1
  • 28
  • 52
  • I see the problem now, thanks. It wasnt intentional @Petr, it was a silly mistake. As to putting the handling code in Subject, it dosent fulfill my purpose. Different circumstances require different handling by Subject(eg: make entry in DB/ make entry in File). I can satisfy that by using inheritance+polymorphism. I can however put a default implementation in Subject(which I currently dont wish to) – Pranav Kapoor Jul 07 '15 at 17:23
  • @PranavKapoor, then you might consider having one `Subject` and several its subclasses for just different treatment. But what you say seems even more appropriate for `Observor` itself: a `DBWriterObservor`, a `FileWriterObservor`, etc — that definitely sounds as an `Observor` responsibility. – Petr Jul 07 '15 at 17:28
  • please correct me if I'm wrong @Petr. Arent observors supposed to care only about the data(in this case ints) they receive? Shouldnt the responsibiity of logging the registering and removing of observors lie with subject itself. – Pranav Kapoor Jul 07 '15 at 17:35
  • @PranavKapoor, oh, you talk about logging observer change, not logging the data? Then yes, that's not for `Observer`. – Petr Jul 07 '15 at 18:12