zoukankan      html  css  js  c++  java
  • 【设计模式】设计模式C++编程实现之观察者模式(ObserverPattern)

    观察者模式定义:
    定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

    观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。


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

    类图

    图一 观察者模式类图

    可以看出,在这个观察者模式的实现里有下面这些角色:

    1. 抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
    2. 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
    3. 具体主题(ConcreteSubject)角色:将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
    4. 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

    观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
    当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。

    关于观察者的一切,主题只知道观察者实现了某个接口(Observer)。主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。
    任何时候我们可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表。在有新的类型的观察者出现时,主题的代码不需要修改。所要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。
    改变主题或观察者其中一方,并不会影响另一方。因为两者是松耦合的。

    气象站实例C++编程实现 (来源于《Head First设计模式》):
    其类图:

    代码:
    //观察者模式C++编程实现
    //author:江南烟雨
    //E-Mail:xiajunhust@gmail.com
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    static int setConditionTimes = 0;//记录设置的总次数
    
    //观察者(布告板)抽象接口
    class Observer{
    public:
    	virtual void update(float temp,float humidity,float pressure) = 0;
    };
    
    //主题抽象接口
    class Subject{
    public:
    	virtual void registerObserver(Observer *o) = 0;//注册观察者
    	virtual void removeObserver(Observer *o) = 0;//删除观察者
    	virtual void notifyObserver() = 0;//当主题状态改变时,通知所有观察者
    };
    
    //布告板显示
    class DisplayElement{
    public: 
    	virtual void display()= 0;
    };
    
    //WeatherData具体类,继承自主题抽象类
    class WeatherData:public Subject{
    private:
    	vector<Observer *> observers;
    	float temperature;
    	float humility;
    	float pressure;
    
    public:
    	WeatherData(){}
    
    	~WeatherData(){
    		vector<Observer*>::iterator pos = observers.begin();
    		for (;pos != observers.end();++pos)
    		{
    			delete (*pos);
    		}
    	}
    
    	void registerObserver(Observer *o){
    		observers.push_back(o);
    	}
    
    	void removeObserver(Observer *o){
    		vector<Observer*>::iterator pos = find(observers.begin(),
    			observers.end(),o);
    		if (pos != observers.end())
    		{
    			observers.erase(pos);
    		}
    	}
    
    	void notifyObserver()
    	{
    		vector<Observer*>::iterator pos = observers.begin();
    		for (;pos != observers.end();++pos)
    		{
    			(*pos)->update(temperature,humility,pressure);
    		}
    	}
    
    	//当从气象站得到更新观测值时,通知观察者
    	void messurementsChanged(){
    		notifyObserver();
    	}
    
    	//设置气象站观测值
    	void setMessurements(float temperature,float humility,float pressure){
    		++setConditionTimes;
    		this->temperature = temperature;
    		this->humility = humility;
    		this->pressure = pressure;
    		messurementsChanged();
    	}
    };
    
    //布告板具体类:目前状况
    class CurrentConditionDisplay:public Observer,public DisplayElement{
    private:
    	float temperature;
    	float humility;
    	
    	Subject *weatherData;
    
    public: 
    	CurrentConditionDisplay(Subject *weatherData){
    		this->weatherData = weatherData;
    		weatherData->registerObserver(this);
    	}
    
    	~CurrentConditionDisplay(){}
    
    	void update(float temp,float humi,float pressure){
    		this->temperature = temp;
    		this->humility = humi;
    
    		display();
    	}
    
    	void display(){
    		cout << "Current conditions: " << temperature << "F degrees and " <<
    			humility << "% humility" << endl;
    	}
    };
    
    //布告板具体类:气象统计类
    class WeatherStatisticsDisplay:public Observer,public DisplayElement{
    private:
    	float avgTemperatuere,maxTemperature,minTemperature;
    	Subject *weatherData;
    
    public: 
    	WeatherStatisticsDisplay(Subject *weatherData){
    		this->weatherData = weatherData;
    		weatherData->registerObserver(this);
    	}
    
    	~WeatherStatisticsDisplay(){}
    
    	void update(float temp,float humi,float pressure){
    		if (1 == setConditionTimes)
    		{
    			this->avgTemperatuere = temp;
    			this->maxTemperature = temp;
    			this->minTemperature = temp;
    		}
    		else{
    			this->avgTemperatuere = (this->avgTemperatuere * (setConditionTimes - 1) + temp) / setConditionTimes;
    			this->maxTemperature = this->maxTemperature > temp ? this->maxTemperature : temp;
    			this->minTemperature = this->minTemperature < temp ? this->minTemperature : temp;
    		}
    
    		display();
    	}
    
    	void display(){
    		cout << "Avg/Max/Min: temperature  " << avgTemperatuere << "/" << 
    			maxTemperature << "/" <<minTemperature << endl;
    	}
    };
    
    int main()
    {
    	WeatherData *weatherData = new WeatherData();
    
    	CurrentConditionDisplay *currentConditionDisplay = new CurrentConditionDisplay(weatherData);
    	WeatherStatisticsDisplay *weatherStatisticsDisplay = new WeatherStatisticsDisplay(weatherData);
    	
    	weatherData->setMessurements(80,65,30.4f);
    	weatherData->setMessurements(82,70,29.2f);
    	weatherData->setMessurements(78,90,29.2f);
    
    	weatherData->removeObserver(weatherStatisticsDisplay);
    
    	cout << "after remove observer WeatherStatisticsDisplay:" << endl;
    	weatherData->setMessurements(80,65,30.4f);
    	weatherData->setMessurements(82,70,29.2f);
    	weatherData->setMessurements(78,90,29.2f);
    
    	return 0;
    }

    运行结果(VS2008 + Win7):


  • 相关阅读:
    Maximum Flow Exhaustion of Paths Algorithm
    ubuntu下安装java环境
    visualbox使用(二)
    vxworks一个超级奇怪的错误(parse error before `char')
    February 4th, 2018 Week 6th Sunday
    February 3rd, 2018 Week 5th Saturday
    February 2nd, 2018 Week 5th Friday
    February 1st, 2018 Week 5th Thursday
    January 31st, 2018 Week 05th Wednesday
    January 30th, 2018 Week 05th Tuesday
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3029446.html
Copyright © 2011-2022 走看看