观察者模式
定义:
我们可以把观察目标理解为主动方、发布方、主体等;把观察者理解为被动方、订阅方、观察器等。目标是整个行为链的源头,其它观察者都依赖于它的变化而作出响应。为了实现低耦合,我们不能使用“直接调用”的方式而需要利用“订阅(清单)-通知”的机制去完成设计。通俗地说就是观察者向目标“订阅”它的改变,而目标发生改变后就“通知”所有已经“订阅”了它的改变的观察者,从而执行“订阅”的内容。这种机制的好处在于降低耦合度,分工明确,目标只负责在自身状态发生改变或做出某种行为时向自身的订阅清单发出“通知”,而不是直接调用观察者的行为(方法);观察者只负责向目标“订阅”它的变化,以及定义自身在收到目标“通知”后所需要做出的具体行为(也就是订阅的内容)。就像我们向出版社订阅报刊一样,出版社有新一期报刊发行时并不是直接跟每位订阅者联系,而是“通知”订阅者名单按顺序给每位订阅者发送所订报刊。
优点:
通过对模型与观察者基类的分析可知,委托与事件的机制几乎消除了这两个模块之间的耦合,灵活性提高了很多。如果需要增加观察者,则只需要覆盖基类抽象方法及把观察目标传递给基类。
案例 1:
有一个拍卖师和诺干买家进行一个艺术品拍卖,这里我们使用观察者模式。这里的拍卖师为被观察者,买家是观察者。
public abstract class observer//首先要创建一个观察者基类
{
public abstract void QuotedPrice();//观察者的报价
}
public abstract class Subject//拍卖者基类
{
public ArrayList observers = new ArrayList();//用于存储观察者的数组
public int _price;//拍卖价格
public void AddObserver(observer person)//添加观察者
{
observers.Add(person);
Console.WriteLine("......{0}加入拍卖",person);
}
public void DeleteObserver(observer person)//删除观察者
{
observers.Remove(person);
Console.WriteLine("......{0}退出拍卖", person);
}
public virtual void QuotedPrice()//通知每一个观察者现在的价格
{
for (int i = observers.Count - 1; i >= 0 ; i--)
{
((observer)observers[i]).QuotedPrice();
}
}
public bool IsOver//是否拍卖结束
{
get
{
if (observers.Count == 0 || observers.Count == 1)
return true;
else
return false;
}
}
}
public class SubjectArt:Subject//具体的拍卖者类
{
public SubjectArt(int _price)//构造函数,构造时,确定起拍价。
{
this._price = _price;
}
public int Price//现在的拍卖价格
{
get
{
return this._price;
}
set
{
if (this._price > value)
return;
else
_price = value;
}
}
public override void QuotedPrice()//拍卖者出家
{
base.QuotedPrice();
if (observers.Count == 1)
{
Console.WriteLine("{0}最终胜出,最终报价为{1}", observers[0], this.Price);
}
else if (observers.Count == 0)
{
Console.WriteLine("本次竞拍流拍...");
}
}
}
public class observerArt:observer//具体的买家类
{
private int _price;//当前买家的出家
private int _topPrice;//买家最高的心理价位
private string _name;//买家的名字
private SubjectArt _subjectArt;//持有拍卖者的引用
public observerArt(string Name,int price,int topPrice, SubjectArt subjectArt)//根据参数进行构造,并把自己作为买家注册给拍卖者
{
this._name = Name;
this._price = price;
this._topPrice = topPrice;
this._subjectArt = subjectArt;
this._subjectArt.AddObserver(this);
}
public override void QuotedPrice()//买家是否再进行出家或者退出
{
if (this._price > _topPrice)
{
Console.WriteLine("{0}退出,当前最高价格{1}", this._name, _subjectArt._price);
this._subjectArt.DeleteObserver(this);
}
else
{
this._price += 1;
this._subjectArt.Price = this._price;
if (this._price >= this._subjectArt.Price)
{
Console.WriteLine("{0}报出最新价格:{1}",this._name,this._price);
}
}
}
}
==================================进行测试===================================================
class Program
{
static void Main(string[] args)
{
SubjectArt subjectArt = new SubjectArt(5);
observerArt personOne = new observerArt("张晓坤",5,15, subjectArt);
observerArt personTwo = new observerArt("张婷婷", 5, 13, subjectArt);
observerArt personThree = new observerArt("王小明", 5, 11, subjectArt);
observerArt personFour = new observerArt("李丽", 5, 14, subjectArt);
observerArt personFive = new observerArt("刘伟", 5, 10, subjectArt);
int n = 0;
while (!subjectArt.IsOver)
{
Console.WriteLine("====第{0}轮竞拍========",n);
subjectArt.QuotedPrice();
n++;
}
Console.ReadKey();
}
}
案例2:
有一个劫匪抢劫了一家银行后逃跑了,有警察追捕他,好心市民看到劫匪会通知警察,劫匪的妻子知道劫匪缺钱后会给他汇钱。这样我们用观察者模式来描述这些,劫匪是被观察者,而警察、好心市民和劫匪妻子都是观察者。以下为代码:
public abstract class ObserverMan//观察者的抽象类
{
public abstract void Update();
}
public abstract class SubjectMan//被观察者的抽象类
{
public List<ObserverMan> observers = new List<ObserverMan>();//所有观察者存储集合
public string location = "";//劫匪要逃亡的地点
/// <summary>
/// 添加观察者
/// </summary>
/// <param name="man"></param>
public virtual void Attact(ObserverMan man)
{
observers.Add(man);
}
/// <summary>
/// 移除观察者
/// </summary>
/// <param name="man"></param>
public virtual void Dettact(ObserverMan man)
{
observers.Remove(man);
}
/// <summary>
/// 通知所有的观察者去做某件事
/// </summary>
public virtual void MessageObserverAll()
{
for (int i = 0; i < observers.Count; i++)
{
observers[i].Update();
}
}
}
public class SubjectBadMan:SubjectMan//具体的劫匪类
{
string Name;//劫匪的名字
public SubjectBadMan(string _name)//劫匪的构造函数
{
this.Name = _name;
}
public void RunAway(string _location)//逃跑到某个地方
{
this.location = _location;
Console.WriteLine("歹徒{0}逃到了{1}",this.Name,this.location);
if (this.observers.Count == 0)
{
Console.WriteLine("你已经安全了,不用再逃亡了....");
}
base.MessageObserverAll();
}
}
public class Police:ObserverMan//警察观察者
{
SubjectBadMan badMan = null;
public Police(SubjectBadMan _badMan)
{
this.badMan = _badMan;
this.badMan.Attact(this);//警察注册观察者
}
public override void Update()//警察要做的事
{
var location = this.badMan.location;
Console.WriteLine("警察 :歹徒已经逃到了{0},赶快部署警力抓捕。",location);
}
}
public class Citizen : ObserverMan//热心市民观察者
{
SubjectBadMan badMan = null;
public Citizen(SubjectBadMan _badMan)
{
this.badMan = _badMan;
this.badMan.Attact(this);//热心市民注册观察者
}
public override void Update()//热心市民要做的事
{
var location = this.badMan.location;
Console.WriteLine("热心市民:歹徒已经逃到了{0},警察赶紧去抓啊", location);
}
}
public class Wife : ObserverMan//妻子要做的事
{
SubjectBadMan badMan = null;
public Wife(SubjectBadMan _badMan)
{
this.badMan = _badMan;
this.badMan.Attact(this);//妻子注册观察者
}
public override void Update()
{
var location = this.badMan.location;
Console.WriteLine("妻子:你到{0}了啊,我给你汇点钱", location);
}
}
===========================================进行测试==========================================
SubjectMan badMan = new SubjectBadMan("张亭亭");
ObserverMan police = new Police(badMan as SubjectBadMan);
ObserverMan citizen = new Citizen(badMan as SubjectBadMan);
ObserverMan wife = new Wife(badMan as SubjectBadMan);
SubjectBadMan man;
man = badMan as SubjectBadMan;
man.RunAway("上海");
Console.WriteLine();
man.Dettact(wife);
man.RunAway("广州");
Console.WriteLine();
man.Dettact(citizen);
man.RunAway("美国");
Console.WriteLine();
man.Dettact(police);
man.RunAway("澳大利亚");
Console.WriteLine();
Console.ReadKey();
使用事件和委托来实现观察者模式