作者:入骨红豆撕不撕 | 来源:互联网 | 2023-10-16 18:27
无论是在现实世界中还是在软件系统中,人们常常会遇到这样一类问题,一个对象的状态改变会引发其他对象的状态改变,如十字路口的交通信号灯,红灯亮则汽车停,绿灯亮则汽车行,再如点击软件中一
无论是在现实世界中还是在软件系统中,人们常常会遇到这样一类问题,一个对象的状态改变会引发其他对象的状态改变,如十字路口的交通信号灯,红灯亮则汽车停,绿灯亮则汽车行,再如点击软件中一个按钮,则会弹出一个窗口。这些对象之间存在一种依赖关系,一个对象的行为会导致依赖它的其他对象发生反应,为了更好地描述这种对象之间的依赖关系,我们需要学习一种新的行为型设计模式,即观察者模式,它是软件设计与开发中使用频率最高的设计模式之一
定义思想:定义对象间一种一对多的依赖关系,使得每当一个对象状态发生改变时,其他相关对象皆得到通知并自动更新
优点:
- 实现了表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制
- 观察者模式支持广播通信,观察目标会向所有注册的观察者发出通知,简化了一对多系统设计的难度
- 观察者模式符合开闭原则的要求,增加新的具体观察者无须修改原有系统代码
缺点:
- 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
适用场景:
- 一个对象必须通知其他对象,而并不知道这些对象时谁
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,降低了对象之间的耦合度
案例:3个英雄打1个怪兽,当怪兽挂掉时需要通知所有英雄,当一个英雄阵亡时不需要通知。
代码:
class AbstractOHero
{
public:virtual void Update() = 0;
};class HeroA : public AbstractOHero
{
public:HeroA(){cout << "英雄A正在打怪兽" << endl;}virtual void Update(){cout << "英雄A停止打怪兽" << endl;}
};class HeroB : public AbstractOHero
{
public:HeroB(){cout << "英雄B正在打怪兽" << endl;}virtual void Update(){cout << "英雄B停止打怪兽" << endl;}
};class HeroC : public AbstractOHero
{
public:HeroC(){cout << "英雄C正在打怪兽" << endl;}virtual void Update(){cout << "英雄C停止打怪兽" << endl;}
};
class AbstractBoss
{
public:virtual void addHero(AbstractOHero* hero) &#61; 0;virtual void deleteHero(AbstractOHero* hero) &#61; 0;virtual void notify() &#61; 0;
};
class BossA : public AbstractBoss
{
public:virtual void addHero(AbstractOHero* hero){pHeroList.push_back(hero);}virtual void deleteHero(AbstractOHero* hero){pHeroList.remove(hero);}virtual void notify(){for (const auto& e : pHeroList){e->Update();}}
private:list<AbstractOHero*> pHeroList;
};
测试&#xff1a;
void test()
{AbstractOHero* heroA &#61; new HeroA();AbstractOHero* heroB &#61; new HeroB();AbstractOHero* heroC &#61; new HeroC();AbstractBoss* bossA &#61; new BossA();bossA->addHero(heroA);bossA->addHero(heroB);bossA->addHero(heroC);cout << "heroC挂了" << endl;bossA->deleteHero(heroC);cout << "Boss死了&#xff0c;通知其英雄" << endl;bossA->notify();delete heroA;delete heroB;delete heroC;delete bossA;
}
运行截图&#xff1a;