Implementing a Subject/Observer pattern with templates
来源:互联网 发布:白百合 知乎 编辑:程序博客网 时间:2024/04/27 02:03
Introduction
The traditional Subject/Observer pattern has one annoying disadvantage: the observer does not get a handle to the notifying subject in its update method. This means that:
- The observer needs to store a pointer to the subject to which it is attached.
- If the observer is attached to multiple objects, it has no way of determining which one of them is notifying him.
The original design pattern
The original design pattern makes use of two base classes:
Subject
and Observer
. The Subject
base class contains all the logic of storing all the attached observers. The Observer class just contains a pure virtual method (update()
), that needs to be filled in by the inheriting observer class. The update()
method of the Observer
class does not get any parameters, which means that a class that inherits from Observer does not know where the notification came from. It is not difficult to add a 'Subject'
parameter to the update method, but since the real subject inherited from the 'Subject'
base class, the observing class always needs to perform a down-cast, which could be dangerous. The solution
Instead of defining two base classes, we will define two template clases. Both template classes will be based on the subject-class that is able to notify other classes (the observers).
template <class T>
class Observer
{
public:
Observer() {}
virtual ~Observer() {}
virtual void update(T *subject)= 0;
};
The first enhancement here is that our pure virtual update method gets a pointer to the subject as argument; not the base Subject class (which is shown hereafter), but the class that was given as parameter to the template definition.
template <class T>
class Subject
{
public:
Subject() {}
virtual ~Subject() {}
void attach (Observer<T> &observer)
{
m_observers.push_back(&observer);
}
void notify ()
{
std::vector<Observer<T> *>::iterator it;
for (it=m_observers.begin();it!=m_observers.end();it++)
(*it)->update(static_cast<T *>(this));
}
private:
std::vector<Observer<T> *> m_observers;
};
Here, we defined the basic
Subject
class/template. The attach method simply adds the observer (which is of the basic Observer<T>
class) to a vector. The notify method simply notifies all observers. Both templates can be used in any situation where the Subject/Observer pattern can be used. The following classes describe how they are used. class Temperature : public Subject<Temperature>
{
public:
Temperature() {}
~Temperature() {}
void temperatureChanged () {notify();}
void getTemperature() {std::cout <<
" Getting the temperature." << std::endl;}
};
Our class) is cast to the type T, the
Temperature
class is a class that monitors the temperature, and notifies its observers when the temperature changes. As you can see all it has to do is call the notify() method. The getTemperature
method simply writes something on the screen, but of course in real-life situations it should return the actual temperature. Taking a look at the implementation of the notify()
method. It simply calls the update()
method of all attached observers, but with itself as argument. Since 'this' (which is the Subjectupdate()
method of the observer will get the correct argument type, as shown in the following example: class PanicSirene : public Observer<Temperature>
{
public:
PanicSirene() {}
~PanicSirene() {}
void update (Temperature *subject)
{
std::cout << "Temperature was changed, sound the sirene"
<< std::endl;
subject->getTemperature();
}
};
As you can see, a pointer to the
Temperature
instance that trigger the notification is given as argument to the update method. The observing class (PanicSirene
in this case) can simply call any method of the notifying subject, in this case simply getTemperature. The following source shows how it is effectively used: Temperature temp;
PanicSirene panic;
temp.attach (panic);
temp.temperatureChanged ();
The following output will be generated:
Temperature was changed, sound the sirene
Getting the temperature.
Observing multiple subjects of a different type
The templates are still easy to use if you need to attach the observer to multiple objects. Suppose that we have a similar subject-class for measuring the pressure.
class Pressure : public Subject{
public:Pressure() {}
~Pressure() {}
void pressureChanged () {notify();}void getPressure() {std::cout << " Getting the pressure."<< std::endl;}
};
If we want to show both the temperature and pressure in a window that shows all environment-related information, we simply create our EnvironmentWindow like this:class EnvironmentWindow : public Observer<Temperature>,public Observer<Pressure>{
public:EnvironmentWindow() {}
~EnvironmentWindow() {}
void update (Temperature *subject) {std::cout <<"Temperature was changed" <<
std::endl; subject->getTemperature();}
void update (Pressure *subject) {std::cout <<"Pressure was changed" <<std::endl; subject->getPressure ();}
};
The class simply inherits twice from theObserver
template, for both theTemperature
and for thePressure
. Notice that we have two update methods here, one for the temperature, one for the pressure. The following example shows how it can be used:Temperature temp;
Pressure press;
EnvironmentWindow win;PanicSirene panic;
temp.attach (win );temp .attach (panic);press.attach (win );temp.temperatureChanged ();press.pressureChanged ();And it shows the following output:Temperature was changedGetting the temperature.
Temperature was changed, sound the sireneGetting the temperature.
Pressure was changedGetting the pressure.
Observing multiple subjects of the same typeIf ourPanicSirene
class needs to verify both the internal temperature and the external temperature, we don't need to modify anything to our implementation of thePanicSirene
class. We simply attach our class instance to bothTemperature
classes.Temperature internalTemp;
Temperature externalTemp;
PanicSirene panic;
internalTemp.attach (panic);externalTemp.attach (panic);
- Implementing a Subject/Observer pattern with templates
- Understanding and Implementing Observer Pattern in C++
- Implementing Repository Pattern With Entity Framework
- subject和observer模式
- Observer Pattern
- Observer pattern
- Observer Pattern
- Observer Pattern
- Observer Pattern
- Observer Pattern
- observer pattern
- Observer Pattern
- Observer pattern
- Observer Pattern
- Observer pattern
- Observer Pattern
- Observer Pattern
- 设计模式---观察者模式(Observer Pattern with java)
- ASP.NET服务器控件之视图状态
- 每日一帖:ResultSet.updateString()
- ASP.NET2.0的控件状态和视图状态探讨
- Vista系统中,雅黑字体突然变细,变得难看。
- swf文件的反编译入门
- Implementing a Subject/Observer pattern with templates
- IIS安装与配置
- 第十七章 使用Log4J进行日志操作(书摘)
- SWF文件结构大解剖
- 细读《Effective C++》之八
- 我们该吃青春饭吗?
- 执行存储过程的方法
- 继续学日语
- DotNet中用到的加密算法总结