观察者模式
作用及特点:两个类有逻辑关系,一个类为主体,另一个类作为观察者,当主体的某一个属性发生变化时,观察者可以根据主体的属性变化做出响应, 一般来说,主体只有一个,观察者可以有好多个,是一对多的关系。
现在马戏团要投喂动物了,假设动物食物的属性可以改变,比如战斧牛排肉很多,是老鹰喜欢吃的食物,老鹰吃完后,剩下带肉的战斧骨头,是老虎喜欢啃的食物,这里食物的属性有个变化。战斧牛排是主体,观察者是老鹰和老虎,当食物属性发生变化时,老鹰和老虎都会做出响应。
主体类
主体类的主要函数为:增加观察者,移除观察者,通知观察者。我们需要一个vector来存储这些观察者。
接下来是主体类的详细代码:Animal.h和Animal.cpp
Animal.h
class ISubject{
public:
virtual ~ISubject() {}
virtual void Add(IObserver* obr) = 0;
virtual void Remove(IObserver* obr) = 0;
virtual void Notify(std::string propertyName) = 0;
};
class AnimalFood : public ISubject
{
public:
virtual void Add(IObserver* obr);
virtual void Remove(IObserver* obr);
virtual void Notify(std::string propertyName);
virtual void changeFoodProperty(std::string property);
std::string m_foodProperty;
private:
std::vector<IObserver*> m_observers;
};
Animal.cpp
void AnimalFood::Add(IObserver* obr)
{
auto iter = std::find(m_observers.begin(), m_observers.end(), obr);
if (iter == m_observers.end())
{
m_observers.emplace_back(obr);
}
}
void AnimalFood::Remove(IObserver* obr)
{
auto iter = std::find(m_observers.begin(), m_observers.end(), obr);
if (iter != m_observers.end())
{
m_observers.erase(iter);
}
}
void AnimalFood::Notify(std::string propertyName)
{
for (const auto& obs : m_observers)
{
obs->propertyChange(propertyName);
}
}
void AnimalFood::changeFoodProperty(std::string property)
{
if (m_foodProperty != property)
{
m_foodProperty = property;
}
Notify("食物类型");
}
观察者类
Animal.h
class IObserver
{
public:
virtual void propertyChange(std::string propertyName) = 0;
ISubject* m_subject = nullptr;
};
class Tiger :public TerrestrialAnimal, public IObserver//老虎类
{
public:
Tiger(const std::string& name);
Tiger(const std::string& name, AnimalFood* subject);
~Tiger();
virtual bool init(const std::string& name);
virtual void running();
virtual void propertyChange(std::string propertyName);
static Tiger* New(const std::string& name);
};
class Eagle :public FlyingBird, public IObserver//老鹰类
{
public:
Eagle(const std::string& name);
Eagle(const std::string& name, AnimalFood* subject);
~Eagle();
virtual bool init(const std::string& name);
virtual void flying();
virtual void propertyChange(std::string propertyName);
static Eagle* New(const std::string& name);
};
Animal.cpp
Tiger::Tiger(const std::string& name, AnimalFood* subject)
{
init(name);
m_subject = subject;
}
void Tiger::propertyChange(std::string propertyName)
{
if (propertyName == "食物类型")
{
if (static_cast<AnimalFood*>(m_subject)->m_foodProperty == "虎类食物")
{
printf("我是%s,马戏团开饭了,我要吃饭!\n\n", m_name.c_str());
}
else
{
printf("我是%s,这是其它动物的食物!\n\n", m_name.c_str());
}
}
}
Eagle::Eagle(const std::string& name, AnimalFood* subject)
{
init(name);
m_subject = subject;
}
void Eagle::propertyChange(std::string propertyName)
{
if (propertyName == "食物类型")
{
if (static_cast<AnimalFood*>(m_subject)->m_foodProperty == "鹰类食物")
{
printf("我是%s,马戏团开饭了,我要吃饭!\n\n", m_name.c_str());
}
else
{
printf("我是%s,这是其它动物的食物!\n\n", m_name.c_str());
}
}
}
输出结果和总结
- 主体类,即被观察的类,需要有容器存放观察者std::vector<IObserver*> m_observers;
- 观察者类,初始化时要记录主体类的指针,很有可能观察者要用到主体类的内容,内容包括主体类的变量和函数。
- 主体类属性变化,通知观察者时,可以告诉观察者是哪个属性发生了变化,观察者可以根据属性,采取行动