C++设计模式编程中的观察者模式使用示例

概述:
最近中国股市起起伏伏,当然了起伏就用商机,小明发现商机后果断想入市,买入了中国证券,他想在电脑客户端上,网页上,手机上,iPad上都可以查看到该证券的实时行情,这种情况下我们应该怎么设计我们的软件呢?我们可以这样:小明的所有客户端上都订阅中国证券这个股票,只要股票一有变化,所有的客户端都会被通知到并且被自动更新。
这就是我们的观察者模式,她定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

类图:

可以看出,在这个观察者模式的实现里有下面这些角色:
抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
具体主题(ConcreteSubject)角色:将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。      
从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要的时候调用每一个观察者共有的Update()方法。这种做法叫做"针对抽象编程"。

概念
观察者模式是讲有一个目标,众多个观察者去“观察”目标。目标是目标抽象类的一个派生类,观察者是观察者抽象类的一个派生类。当目标类的数据改变,所有对应的观察者对应去更新自己的状态
可以使用的情况:比如有一个世界时钟程序,有多个图形时钟去显示比如北京时区,巴黎时区,等等。如果设置一个北京时间,那么其他时钟图形都需要更新(加上或者减去时差值)。典型的图形界面设计随处可见,一个温度程序,在温度湿度等条件改变时,要更新多种显示图形来呈现。

实例
使用时,首先定义一个Subject的类对象,然后再定义多个Observer类(派生类)对象,每个Observer对象指定自己被注册到哪个Subject对象内。

示例:

#include<vector>
#include<iostream>
#include<string>
using namespace std;

class Subject;

class Observer{          //观察者抽象类
public:
 virtual void update(Subject *base)=0;
protected:
 Subject * _subject;
};

class Subject{          //目标抽象类
public:
 string s1;            //数据值,可以作为私有数据,然后定义一个借口去返回值,这里为了省事
 int i1;               //数据值
 void regiObserver(Observer *obs){
  _observer.push_back(obs);
   cout<<"已注册"<<endl;
 }
 void deleObserver(Observer *obs){
  _observer.pop_back();
 }
 void notify(){        //更新所有的观察者
  vector<Observer *>::iterator it;
  for(it = _observer.begin(); it != _observer.end(); it++)
   (*it)->update(this);
 }
private:
 vector<Observer *> _observer;    //观察者容器
};

class FSubject:public Subject{
public:
 void set(string s,int i){
  s1 = s;
  i1 = i;
  notify();                  //通知观察者。主函数的执行顺序已经保证了所有的观察者都已经进入容器内
 }
};

class FObserver :public Observer{  //第一个观察者派生类
public:
 FObserver(Subject *base):Observer(){
  _subject = base;
  _subject->regiObserver(this);
 }
 void update(Subject *base){
  s1 = base->s1;
  i1 = base->i1;
  display();
 }
 void display(){
  cout<<"更新值,第一个\n"<<s1<<endl;
  cout<<i1<<endl;
 }
private:
 string s1;
 int i1;
};

class SObserver:public Observer{  //第二个观察者派生类
 public:
 SObserver(Subject * base){
  _subject = base;
  _subject->regiObserver(this);
 }
 void update(Subject *base){
  s1 = base->s1;
  i1 = base->i1;
  display();
 }
  void display(){
  cout<<"更新值,第二个\n"<<s1<<endl;
  cout<<i1<<endl;
 }
private:
 string s1;
 int i1;
};

int main()
{
 FSubject * sub = new FSubject;
 FObserver * one = new FObserver(sub);
 SObserver * two = new SObserver(sub);
 sub->set("ok",3);
 return 0;

}
 Subject 类中的容器对象维护者所有对观察者的引用,目的是在notify中去更新所有的观察者,即通过遍历去调用观察者->update()。

观察者中的update()作用是完成观察者需要完成的事,比如在上例中,去更新自身保存的副本值,然后并显示出来。

Observer类中有一个Subject指针非常重要,在观察者的派生类的构造函数,需要去把自身的this传递过去进行注册。

Observer中有和Subject同样的数据,也可以设置为局部变量,仅仅是完成观察者需要做的事就行,而不必存储。

(0)

相关推荐

  • 简单了解设计模式中的装饰者模式及C++版代码实现

    由遇到的问题引出的装饰模式 在 OO 设计和开发过程,可能会经常遇到以下的情况:我们需要为一个已经定义好的类添加新的职责(操作),通常的情况我们会给定义一个新类继承自定义好的类,这样会带来一个问题(将在本模式的讨论中给出).通过继承的方式解决这样的情况还带来了系统的复杂性,因为继承的深度会变得很深. 而装饰提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合. 有关这些内容在讨论中进一步阐述. 模式选择 装饰模式典型的结构图为: 在 结 构 图 中 , ConcreteComponen

  • 详解C++设计模式编程中建造者模式的实现

    建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.这是建造者模式的标准表达,不过看着让人迷惑,什么叫构建和表示的分离?一个对象使用构造函数构造之后不就固定了,只有通过它方法来改变它的属性吗?而且还要同样的构建过程搞出不同的表示,怎么可能呢?多写几个构造函数? 其实多写几个构造函数,根据不同参数设置对象不同的属性,也可以达到这样的效果,只是这样就非常麻烦了,每次要增加一种表示就要添加一个构造函数,将来构造函数会多得连自己都不记得了,这违背了开放-封闭的原则. 要

  • 详解C++设计模式编程中策略模式的优缺点及实现

    策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法的变化不会影响到使用算法的客户.策略模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦.策略模式将逻辑(算法)封装到一个类(Context)里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现.State 模式也有类似的功能,他们之间的区别将在讨论中给出. UML图

  • C++编程中使用设计模式中的policy策略模式的实例讲解

    在看<C++设计新思维>的时候,发现在一开始就大篇幅的介绍策略模式(policy),策略模式不属于经典设计模式中的一种,但是其实在我们日常的开发中是必不可少的.policy,策略,方针,这里的意思是指把复杂功能的类尽量的拆分为功能单一的简单类的组合,简单的类只负责单纯行为或结构的某一方面.增加程序库的弹性,可复用性,可扩展性.policy是一个虚拟的概念,他定义了某一类class的一些接口规范,并不与C++语法的关键字对应,只是一个抽象的概念. 实例1: //policy模式的常见使用实例sm

  • 举例解析设计模式中的工厂方法模式在C++编程中的运用

    工厂方法模式不同于简单工厂模式的地方在于工厂方法模式把对象的创建过程放到里子类里.这样工厂父对象和产品父对象一样,可以是抽象类或者接口,只定义相应的规范或操作,不涉及具体的创建或实现细节. 其类图如下: 实例代码为: #pragma once class IProduct { public: IProduct(void); virtual ~IProduct(void); }; #pragma once #include "iproduct.h" class IPad : public

  • 使用设计模式中的单例模式来实现C++的boost库

    线程安全的单例模式 一.懒汉模式:即第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例. 需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety. 使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈. 1.静态成员实例的懒汉模式: class Singleton { private: static Singleton* m_instance; Sing

  • 解析设计模式中的Prototype原型模式及在C++中的使用

    原型模式的意图是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性  当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或者 当一个类的实例只能有几个不同状态组合中的一种时.建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些. 关于这个模式,突然想到了小时候看的<西游记>,齐天大圣孙悟空再发飙的时候可以通过自己头上的 3 根毛立马复制出来成千上万的孙悟空,对付小妖怪很管用(数量最重要). 原

  • C++设计模式编程中proxy代理模式的使用实例

    代理模式典型的结构图为: 实际上,代理模式的想法非常简单. 代理模式的实现: 完整代码示例(code):代理模式的实现很简单,这里为了方便初学者的学习和参考,将给出完整的实现代码(所有代码采用 C++实现,并在 VC 6.0 下测试运行). 代码片断 1:Proxy.h //Proxy.h #ifndef _PROXY_H_ #define _PROXY_H_ class Subject{ public: virtual ~Subject(); virtual void Request() =

  • 浅析设计模式中的代理模式在C++编程中的运用

    由遇到的问题引出代理模式 至少在以下集中情况下可以用代理模式解决问题: 创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成,GoF 称之为虚代理(Virtual Proxy): 为网络上的对象创建一个局部的本地代理,比如要操作一个网络上的一个对象(网络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成,GoF 称之为远程代理(Remote Proxy): 对对象进行控制访问的时候,比如在 Jive 论坛中不同权限的用户(如管理员.普通用户等)将获得

  • 深入解析C++编程中对设计模式中的策略模式的运用

    策略模式也是一种非常常用的设计模式,而且也不复杂.下面我们就来看看这种模式. 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 角色: 抽象策略角色(Strategy): 抽象策略类. 具体策略角色(ConcreteStrategy):封装了继续相关的算法和行为. 环境角色(Context):持有一个策略类的引用,最终给客户端调用. UML图: 例子: #include <iostream> using names

随机推荐