一,概述
观察者<Observer>模式(有时又被称为发布-订阅<Publish/Subscribe>模式、模型-视图<Model/View>模式、源-收听者<Source/Listener>模式或从属者<Dependents>模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。
二,示例
题目描述:公司里有的员工偷懒,看股票,看NBA。老板回来需要有人通知他们,然后再好好干活。通知大家的任务交给前台。
1)双向耦合的代码 (读此代码之前先看两个类互相包含)
缺点:前台通知类和看股票者相互耦合。如果再想增加一个看NBA的类就违反“开放-- 封闭原则”
StockObserver.h类()
#include <iostream>
#include <string>
using namespace std;
class Secretary;
//看股票的同事
class StockObserver
{
private:
string name;
Secretary *sub;
public:
StockObserver(string name, Secretary *sub)
{
this->name = name;//这里一定要加上this
this->sub = sub;
}
void Update()
{
//cout<<sub->getAction()<<name<<"关闭股票行情,继续工作!"<<endl;
cout<<name<<"!!关闭股票行情,继续工作!"<<endl;
}
};
Secretary.h
#include <iostream>
#include <list>
#include <algorithm>
#include "StockObserver.h"
using namespace std;
template<typename T>
struct display
{
void operator()( T &observer)
{
observer.Update();
}
};
class Secretary
{
//同事列表
private:
list<StockObserver> observers;// = new List<StockObserver>();
string action;
public:
//增加
friend class StockObserver;
void Attach(StockObserver observer)
{
observers.push_back(observer);
}
//减少
void Detach(StockObserver observer)
{
observers.pop_back();
}
//通知
void Notify()
{
for_each(observers.begin(),observers.end(),display<StockObserver>());
}
//前台状态
void SecretaryAction(string value)
{
action = value;
}
};
main.cpp(客户端程序)
#include <iostream>
#include "Secretary.h"
using namespace std;
int main()
{
//前台小姐童子喆
Secretary *tongzizhe= new Secretary();
//看股票的同事
StockObserver tongshi1("魏关姹", tongzizhe);
StockObserver tongshi2 ("易管查", tongzizhe);
//前台记下了两位同事
tongzizhe->Attach(tongshi1);
tongzizhe->Attach(tongshi2);
//发现老板回来
tongzizhe->SecretaryAction( "老板回来了!");
//通知两个同事
tongzizhe->Notify();
getchar();//防止退出的
return 0;
}
2)解除耦合实践一:(C#)
增加了抽象的观察者,方便扩展各种类型的扩展者。
using System;
using System.Collections.Generic;
using System.Text;
namespace 观察者模式
{
class Program
{
static void Main(string[] args)
{
//前台小姐童子喆
Secretary tongzizhe = new Secretary();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹", tongzizhe);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("易管查", tongzizhe);
//前台记下了两位同事
tongzizhe.Attach(tongshi1);
tongzizhe.Attach(tongshi2);
//发现老板回来
tongzizhe.SecretaryAction = "老板回来了!";
//通知两个同事
tongzizhe.Notify();
Console.Read();
}
}
//前台秘书类
class Secretary
{
//同事列表
private IList<Observer> observers = new List<Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer);
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
o.Update();
}
//前台状态
public string SecretaryAction
{
get { return action; }
set { action = value; }
}
}
//抽象观察者
abstract class Observer
{
protected string name;
protected Secretary sub;
public Observer(string name, Secretary sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
//看股票的同事
class StockObserver : Observer
{
public StockObserver(string name, Secretary sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SecretaryAction, name);
}
}
//看NBA的同事
class NBAObserver : Observer
{
public NBAObserver(string name, Secretary sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SecretaryAction, name);
}
}
}
3)解除耦合实践二:(C#)
改进:由于老板来了会自己通知职员,前台也可以偷偷通知职员老板来了。所以增加一个通知者接口。
using System;
using System.Collections.Generic;
using System.Text;
namespace 观察者模式
{
class Program
{
static void Main(string[] args)
{
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹", huhansan);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("易管查", huhansan);
huhansan.Attach(tongshi1);
huhansan.Attach(tongshi2);
huhansan.Detach(tongshi1);
//老板回来
huhansan.SubjectState = "我胡汉三回来了!";
//发出通知
huhansan.Notify();
Console.Read();
}
}
//通知者接口
interface Subject
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
class Secretary : Subject
{
//同事列表
private IList<Observer> observers = new List<Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer);
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
o.Update();
}
//前台状态
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
class Boss : Subject
{
//同事列表
private IList<Observer> observers = new List<Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer);
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
o.Update();
}
//老板状态
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//抽象观察者
abstract class Observer
{
protected string name;
protected Subject sub;
public Observer(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
//看股票的同事
class StockObserver : Observer
{
public StockObserver(string name, Subject sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SubjectState, name);
}
}
//看NBA的同事
class NBAObserver : Observer
{
public NBAObserver(string name, Subject sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SubjectState, name);
}
}
}
三,观察者模式
发布--订阅模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者基本代码:抽象通知者类,具体实现通知者类,抽象观察者类,具体实现观察者类
抽象通知者为具体实现者父类,负责通知注册的观察者类
class Program
{
static void Main(string[] args)
{
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.SubjectState = "ABC";
s.Notify();
Console.Read();
}
}
abstract class Subject //抽象通知者
{
private IList<Observer> observers = new List<Observer>();
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
//具体通知者
class ConcreteSubject : Subject
{
private string subjectState;
//具体通知者状态
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
abstract class Observer //抽象观察者
{
public abstract void Update();
}
class ConcreteObserver : Observer //具体观察者
{
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver(
ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
//更新
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("观察者{0}的新状态是{1}",
name, observerState);
}
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
四,观察者模式的特点
问题:
1)将一个系统分割成一系列相互协作的类有一个不好的副作用:需要维护相对对象的一致性
2)我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便
观察者优点:
1)让耦合的双方都依赖于抽象,而不是依赖于具体。抽象不变,具体会变化