• 设计模式观察者模式


    观察者模式Observer):

        定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题的对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。


    1.将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护的相关对象之间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
    2.什么时候使用观察者模式?当一个对象的改变需要同时改变其他对象的时候。而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
    3.一个抽象模型有两个方面,其中一方面依赖于另一方面,这是用观察者模式可以将这两者封装在独立的对象中使它们给子独立地改变和复用。
    4.观察者模式所做的工作其实就是在接触耦合。让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

    观察者实现代码

    #pragma once
    
    #include <set>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    //Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
    //这个接口叫做更新接口,抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个Update()
    //方法,这个方法叫做更新方法。
    
    class CObserver
    {
    public:
    	virtual void Update() = 0;
    };
    
    //Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用
    //保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提一个接口,可以增加和删除观察者对象。
    
    class CSubject
    { 
    private:
    	set <CObserver *> m_HashMemory;
    public:
    	CSubject()
    	{
    		m_HashMemory.clear();
    	}
    	~CSubject()
    	{
    		for each(CObserver *i in m_HashMemory)
    		{
    			delete i;
    		}
    	}
    	void Attach(CObserver *pObserver)
    	{
    		m_HashMemory.insert(pObserver);
    	}
    	void Detach(CObserver *pObserver)
    	{
    		m_HashMemory.erase(pObserver);
    		delete pObserver;
    	}
    	void Notify()
    	{
    		for each(CObserver *i in m_HashMemory)
    		{
    			i->Update();
    		}
    	}
    };
    
    //ConcreteSubject类,叫做具体主题或具体通知者,将有关状态存入具体
    //观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出
    //通知。具体主题角色通常用一个具体子类体现。
    
    class CConcreteSubjuct : public CSubject
    {
    private:
    	string m_strSubjectState;
    public:
    	CConcreteSubjuct(const string &strName)
    	{
    		m_strSubjectState = strName;
    	}
    	string GetName()
    	{
    		return m_strSubjectState;
    	}
    };
    
    //ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的接口,
    //以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向
    //具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
    class CConcreteObserver : public CObserver
    {
    private:
        string m_strName;
    	string m_strObserverState;
    	CConcreteSubjuct *m_pSubject;
    public:
    	CConcreteObserver(CConcreteSubjuct * pSubject ,const string &strName)
    	{
    		m_pSubject = pSubject;
    		m_strName = strName;
    	}
    	void Update()
    	{
    		m_strObserverState = m_pSubject->GetName();
    		cout<<"观察者"<<m_strName<<"的新状态是"<<m_strObserverState<<endl;
    	}
    };
    
    客户端使用代码

    #include "stdafx.h"
    #include "ObserverMode.h"
    #include <windows.h>
    
    using namespace std;
    
    int main()
    {
    	CConcreteSubjuct *pQianTai = new CConcreteSubjuct("QianTai");
    	CConcreteObserver *pYuanGongA = new CConcreteObserver(pQianTai ,"YuanGongA");
    	CConcreteObserver *pYuanGongB = new CConcreteObserver(pQianTai ,"YuanGongB");
    	CConcreteObserver *pYuanGongC = new CConcreteObserver(pQianTai ,"YuanGongC");
    	pQianTai->Attach(pYuanGongA);
    	pQianTai->Attach(pYuanGongB);
    	pQianTai->Attach(pYuanGongC);
    	pQianTai->Notify();
    	pQianTai->Detach(pYuanGongB);
    	pQianTai->Notify();
    	delete pQianTai;
    
    	return 0;
    }
    运行结果

    观察者的不足和优化改进以及后续思路的扩展
        观察者的不足就是通知者和观察者需要相互知道才行,比如提醒所有人的时候就要调用给所有人的Update方法,这样局限性也比较大,解决办法就是直接定义函数指针就OK,我们只要把所有的被通知者需要通知的函数地址传给前台观察者就行了,C++需要传函数指针,C#需要使用委托就行,其实想一下,这个思路现在的扩展应用不就是我们常用的回调函数吗?
  • 相关阅读:
    Codeforces 449D:Jzzhu and Numbers
    51nod 1040:最大公约数之和
    51nod 1179:最大的最大公约数
    51nod 1406:与查询
    51nod 1354:选数字
    51nod 1616:最小集合
    Codeforces:Colored Balls
    素性测试
    秒转换成年月日时分秒 和复制文本到剪贴板
    vue项目中获取cdn域名插件
  • 原文地址:https://www.cnblogs.com/csnd/p/12062343.html
Copyright © 2020-2023  润新知