步步为营 .NET 设计模式学习笔记 十二、Observer (观察者模式)
概述
在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作(Collaboration)。观察者模式是满足这一要求的各种设计方案中最重要的一种。
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]
<Design Pattern>结构图
图1 Observer模式结构图
角色说明:
Subject(被观察的对象接口)
规定ConcreteSubject的统一接口;
每个Subject可以有多个Observer;
ConcreteSubject(具体被观察对象)
维护对所有具体观察者的引用的列表;
状态发生变化时会发送通知给所有注册的观察者。
Observer(观察者接口)
规定ConcreteObserver的统一接口;
定义了一个update()方法,在被观察对象状态改变时会被调用。
ConcreteObserver(具体观察者)
维护一个对ConcreteSubject的引用;
特定状态与ConcreteSubject同步;
实现Observer接口,通过update()方法接收ConcreteSubject的通知。
生活中的例子
观察者定义了对象间一对多的关系,当一个对象的状态变化时,所有依赖它的对象都得到通知并且自动地更新。拍卖演示了这种模式。每个投标人都有一个标有数字的牌子用于出价。拍卖师开始拍卖时,他观察是否有牌子举起出价。每次接受一个新的出价都改变了拍卖的当前价格,并且广播给所有的投标人进行新的出价。
图2 使用拍卖例子的观察者模式
示例用例图:
十字路口的红绿灯,行人和司机都看红绿灯的变化来行动,司机看到向左转的指示灯和行人看到绿灯过马路这一情景,正好符合我们的观察者模式,司机(Drive)和行人(Pedestrian)是具体观察者而指示灯(PilotLamp)是观察者接口和红绿灯(TrafficLight)具体被观察对象,先看用例图:
代码设计:
先创建PilotLamp.cs:
public inte易做图ce PilotLamp { /// <summary> /// green light /// </summary> void TurnOn(); /// <summary> /// notice /// </summary> string Notice { get; set; } }
再创建DelegateEvent.cs:
public delegate void EventHandler();
再创建TrafficLight.cs:
public class TrafficLight : PilotLamp { public event EventHandler Notices; private string notice; #region GreenLight 成员 public void TurnOn() { if (Notices != null) Notices(); } public string Notice { get { return notice; } set { notice = value; } } #endregion }
再创建Driver.cs:
public class Driver { private string Name; private PilotLamp greenLight; public Driver(string name, PilotLamp greenLight) { this.Name = name; this.greenLight = greenLight; } public void GoLeft() { Console.WriteLine(string.Format("{1}司机,{0},请向左开车.",
greenLight.Notice, Name)); } }
再创建Pedestrian.cs:
public class Pedestrian { private string Name; private PilotLamp greenLight; public Pedestrian(string name, PilotLamp greenLight) { this.Name = name; this.greenLight = greenLight; } public void GoThrough() { Console.WriteLine( string.Format("{0}同志,{1},请向前走.",
Name, greenLight.Notice)); } }
最后再调用:
public partial class Run : Form { public Run() { InitializeComponent(); } private void btnRun_Click(object sender, EventArgs e) { TrafficLight trafficLight = new TrafficLight(); Driver driverOne = new Driver("张三", trafficLight); Driver driverTwo = new Driver("李四", trafficLight); Pedestrian pedestrianOne = new Pedestrian("王五", trafficLight); Pedestrian pedestrianTwo = new Pedestrian("麻六", trafficLight); trafficLight.Notices += new Observer.EventHandler(driverOne.GoLeft); trafficLight.Notices += new Observer.EventHandler(driverTwo.GoLeft); trafficLight.Notices += new Observer.EventHandler(pedestrianOne.GoThrough); trafficLight.Notices += new Observer.EventHandler(pedestrianTwo.GoThrough); trafficLight.Notice = "绿灯亮了."; trafficLight.TurnOn(); } }
输出时选控制台应用程序如图:
结果如下图: