二十二.行为型设计模式——Observer Pattern(观察者模式)
-
定义:
定义对象间的一种一对多依赖关系,使得每当一个对象改变状态,则其相关依赖对象皆得到通知并被自动更新。
UML类图如下:
其中类和对象的关系为:
1.Subject(被观察对象):了解其多个观察者,任意数量的观察者可以观察一个对象;提供一个接口用来缚定(attaching)及分离(detaching)观察者对象。
2.ConcreteSubject(具体被观察对象):储存具体观察者(ConcreteObserver)有兴趣的状态;当其状态改变时发送一个通知给其所有的观察者对象。
3.Observer(观察者):定义一个更新(updating)接口,在一个被观察对象改变时应被通知。
4.ConcreteObserver(具体观察者):维护一个对ConcreteSubject对象的引用;储存状态,状态需与ConcreteSubject保持一致;实现观察者更新(update)接口以保持其状态与ConcreteSubject对象一致。
典型应用的顺序图如下:
具体观察者状态的更改需要通知给各个观察者。
-
实例1——猫和老鼠
老鼠外出要时刻小心猫。当猫大叫一声“喵”,所有老鼠开始纷纷逃跑。这种情况就可以对应于观察者模式。UML类图如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface Observer
{
//观察者的响应,这里是老鼠见到猫的反映
void Response();
}
public interface Subject
{
//针对哪些观察者,这里指猫要捕捉的对象-老鼠
void AimAt(Observer obs);
}
public class Mouse : Observer
{
private string name;
private Cat cat;
public Mouse(string name, Subject subj)
{
this.name = name;
subj.AimAt(this);
}
public void Response()
{
Console.WriteLine(name + "努力逃跑");
}
}
public class Cat : Subject
{
private ArrayList observers;
public Cat()
{
this.observers = new ArrayList();
}
public void AimAt(Observer obs)
{
this.observers.Add(obs);
}
public void Cry()
{
Console.WriteLine("猫叫了!");
foreach (Observer obs in this.observers)
{
obs.Response();
}
}
}
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
Mouse mouse1 = new Mouse("小老鼠", cat);
Mouse mouse2 = new Mouse("大老鼠", cat);
cat.Cry();
Console.Read();
}
}
-
实例2——股票的变化
观察者模式也可以应用到股票系统中,每当个股发生变化,这种变化都会通知给注册的投资者。UML类图如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//被观察对象—个股
abstract class Stock
{
private string symbol;
protected double price;
private ArrayList investors = new ArrayList();
public Stock(string symbol, double price)
{
this.symbol = symbol;
this.price = price;
}
//附加要通知的投资者
public void Attach(Investor investor)
{
investors.Add(investor);
}
//分离要通知的投资者
public void Detach(Investor investor)
{
investors.Remove(investor);
}
//通知需要知会的投资者
public void Notify()
{
foreach (Investor i in investors)
i.Update(this);
}
//股价每一次赋值通知其所有的投资者
public double Price
{
get { return price; }
set
{
price = value;
Notify();
}
}
//个股标志
public string Symbol
{
get { return symbol; }
set { symbol = value; }
}
}
//具体被观察对象
class IBM : Stock
{
public IBM(string symbol, double price) : base(symbol, price) { }
}
//观察者
interface IInvestor
{
void Update(Stock stock);
}
//具体观察者
class Investor : IInvestor
{
private string name;
private Stock stock;
public Investor(string name)
{
this.name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("通知到股民{0} {1}最新股价为:{2:C}", name, stock.Symbol, stock.Price);
}
public Stock Stock
{
get { return stock; }
set { stock = value; }
}
}
class Program
{
static void Main(string[] args)
{
//创建股民
Investor s = new Investor("张三");
Investor b = new Investor("李四");
//创建个股IBM并且附加上投资的股民
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(s);
ibm.Attach(b);
//变更股价,其投资的所有股民都得到通知
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
Console.Read();
}
}
-
优势和缺陷:
观察者模式抽象了被观察对象与观察者对象的连接,提供了广播式的对象间通信,并且容易增加新的观察者对象。观察者模式的缺陷是对象间的关系难以理解,在某种情况下会表现低效能。
-
应用情景:
下面的情景很适合应用观察者模式:
1.对一个对象的变化请求需要其他对象也变化,并且其他要变化对象的数量不明确。
2.一个对象需要通知其他对象而不需要掌握其他对象的识别方法。