设计模式学习总结:(4)观察者模式

现实生活中,这样的例子太多了,一个对象的状态受另外一个对象的影响。比如,进度条根据上传的百分比而变化,红灯停绿灯行。。。。。这样的业务数不胜数。甚至我们有时候心情也是随着很多经历而变化。在开发过程中,这样的业务当然也是很多的,但是,稍有不慎,我们可能会实现出比较麻烦的代码。而设计模式中有一种模式对于解决这样的业务具有很好作为,那就是观察者模式。简而言之就是:我们有一个目标,还有很多观察者,当目标变化,观察者们将作出相关的变化。

观察者模式:

看看书上的定义,也是行为模式

意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变,所有依赖于它的对象都得到通知并将自动更新。


对于这样一种业务,我们很自然的需要两种角色:目标观察者

 确实,为了遵循"开闭"原则,我们两种对象创建两种对象的抽象基类,这样便于扩展和维护。于是就有四个基本的结构。

抽象目标抽象观察者具体目标具体观察者

书上给出的结构图:

对这个结构图,需要注意到是目标的  Notify()和 观察者的 update()两个方法。

抽象代码可以实现为:

抽象目标:

class AbtSubject
{
private:
    vector<AbtObserver *>  _obArr;   //抽象目标有观察者
public: virtual void addObserver(AbtObserver *observer); //自己实现 virtual void rmObserver(AbtObserver *observer); //要实现 virtual void notify(); } void AbtSubject::notify() { for(auto obs:_obArr) { obs.update(); } }

注:虚析构和构造函数未给出。

抽象观察者:

class AbtObserver
{
protect:
    AbtObserver();
    virtual ~AbtObserver();
public:
    virtual void update()=0;
}

具体目标,假如是红绿灯:

enum RGcolor
{ red, green, yellow }
class RGLight:public AbtSubject { private: RGcolor _color; public: RGcolor getColor() { return _color; } RGcolor setColor(RGcolor color) { _color = color; }
void colorChange()
{
notify();
}
}

简单的实现:

具体观察者:

#include<iostream>
//如果有必要,引入subject头文件

class WalkingPerson()
{
private:
    AbSubject * _subject;
public:
    void update();
    void walk();
    void stop();
}
void WalkingPerson::update()
{
    switch(_subject->getColor())
    {
        case red:
             this->stop();
             break;
        case green:
             this->walk();
             break;
         }
}

这样具体思路也就是这样,当然还有很多细节,比如构造函数的实现,这可能还得通过具体业务额定。至少到这里我们已经知道这样四个角色的含义了。

抽象目标:

自然的包含了一系列的观察者,定义了一些抽象接口,比如通知函数notify,用来通知自己拥有的那一系列观察者。和一些后代接口,比如添加删除观察者。

抽象观察者:

定义如何反应目标的通知的抽象方法update()

具体的目标:

具体实现。

具体观察者:

通过包含自己观察者来保存与目标的状态。

这样的一个结构很明显的好处就是:

1.目标和观察者耦合度最小:因为都是建立在两个抽象类之上,通过多态特性,可以把两种不同类之间的耦合度达到最小,可以动态 添加具体观察者而不影响其他观察者。

2.广播优势:也就是说发出信号而无需知道观察者是谁,一视同仁。

缺陷也很明显:

确实存在一种依赖关系,这种依赖关系可能导致未知影响,甚至是对于观察者的依赖对象的变化。还有目前的目标假设在一个,有时候存在多种目标,而需要观察者知道是哪个目标。

好处可以通过举返利,比如将person类耦合到目标类中,但是这样的违背了面向对象的原则,这里就不举例了。

设计模式:可复用面向对象软件的基础 这本书上还给了一些在实际开发过程中额外的复杂的依赖关系。

1."创建目标到其观察者之间的映射":这是作者假设如果目标过多而观察者比较少,额外的空间开销显得没有必要,所以通过映射(hash)方式来处理会更好,但是也可能造成观察者的开销。

2."观察多个观察者",我们上面的例子是只有一个subject,如果有多个,我们可能还需要将具体suject作为update的参数,这样观察者可以以此判断是什么目标发生变化。

3."判断是谁的更新",这个嘛,看了很久,上面例子中,我是在红绿灯颜色发生变化的时候调用的notify方法,也就是书上的第一个方案,有具体subject自己决定什么时候调用notify通知观察者,这种的坏处是可能存在效率问题。第二种,是有客户(使用者)自己去调用,这种方式坏处是增加客户责任,同时使用者的对要求也比较高。

4."对已经删除目标悬挂引用",就是说如果有个目标对象被删除,如何处理其相关观察者引用这个被删除对象的问题。

5."发出通知前确保目标状态的一致性",在发送通知的时候很可能目标和观察者直接的状态并不统一。

6."避免特定于观察者的更新协议——推/拉模型",推模型:广播由目标向观察者发送改变的信息。拉模型:有观察者自己询问改变信息。

7."显示指定感兴趣的信息",可以在添加的时候讲观察者感兴趣的信息告诉目标,更新的时候就传给目标。

8."封装复杂的更新",当目标和观察者之间的依赖关系过于复杂,应该建立一个中间对象来处理这种复杂的关系,书上给出了结构图。

可以看到,在目标和观察之间建立了一个manage对象。在理解过程中对一些业务其实还处在朦胧阶段,我想也许在将来的工作中,可以加深对该模式的理解,共勉。

原文地址:https://www.cnblogs.com/wuweixin/p/5425099.html