观察者模式
本片博客将介绍观察者模式,观察者模式用于描述对象之间的依赖关系,为实现多个对象的联动提供一种解决方案,是一种使用频率非常高的设计模式。
模式分类
行为型设计模式。
模式产生的原因
在软件系统中,对象并不是孤立存在的,一个对象行为的改变可能会导致一个或者多个其他与之相关的对象行为发生改变。他们之间将产生联动,所谓牵一发而动全身。为了更好的描述对象之间存在的这种一对多或者一对一的关系,观察者模式应运而生,它定义了对象之间一种一对多的依赖关系,让一个对象改变可以影响其他对象。
模式灵感的来源
在日常生活中,交通灯指挥着日益拥挤的城市交通,当红灯亮起,来往的汽车将停止;绿灯亮起,汽车可以继续前进。在这个过程中,交通信号灯是汽车的观察目标,而汽车是交通灯的观察者。随着交通灯的变化,汽车的行为也发生了变化,一盏交通灯可以指挥多辆汽车。
模式类图
观察者模式中通常包含以下四种对象:
Subject(观察目标):
观察目标是被观察的对象,在目标中会定义一个观察者集合,当观察目标发生改变时,会调用集合中每个观察者对应的方法。
ConcreteSubject(具体观察目标):
具体观察目标,,通常包含经常发生改变的数据,当他的状态发生改变时,将向它的各个观察者发出通知,同时他还会实现抽象观察目标中的抽象方法。
Observer(观察者):
观察者将对观察目标的改变作出反应,观察者一般定义为接口,该接口声明了更新数据的方法。
ConcreteObserver(具体观察者):
在具体观察者中维护了一个指向具体目标对象的引用,,通常在在实现时,会通过观察目标的方法将自己添加到其观察者集合中。也就是说,观察目标中观察者的添加是由观察者本身完成的。
代码实现
例子:当股票购买者所购买的股票价格发生变化的时候,系统将自动发送通知给购买该股票的所有股民。试使用观察者模式设计该系统。
观察目标:交易系统
using System.Collections.Generic;
namespace Observer.Observer.Question6
{
public class TradingSystem
{
private static TradingSystem _instance;
public static TradingSystem GetInstance
{
get
{
if (_instance == null)
{
_instance = new TradingSystem();
}
return _instance;
}
}
private readonly Dictionary<string, List<Buyer>> _buyerList =
new Dictionary<string, List<Buyer>>();
public void Add(string stockName, Buyer buyer)
{
if (_buyerList.ContainsKey(stockName))
{
if (_buyerList[stockName] != null)
{
_buyerList[stockName].Add(buyer);
}
else
{
_buyerList[stockName] = new List<Buyer>();
_buyerList[stockName].Add(buyer);
}
}
else
{
_buyerList.Add(stockName, new List<Buyer>());
_buyerList[stockName].Add(buyer);
}
}
public void Remove(string stockName, Buyer buyer)
{
}
public void Notify(Message message)
{
foreach (var buyer in _buyerList[message.StockName])
{
buyer.GetMessage(message);
}
}
}
}
观察者类
namespace Observer.Observer.Question6
{
public abstract class Buyer
{
public string Name { get; set; }
public Buyer(string name)
{
Name = name;
}
public abstract void GetMessage(Message message);
}
}
股票信息类:
namespace Observer.Observer.Question6
{
public class Message
{
public int Money;
public string StockName;
}
}
股票类:
using Observer.Observer.Example;
namespace Observer.Observer.Question6
{
public abstract class Stock
{
private int _money;
public int Money
{
get => _money;
set
{
_money = value;
OnMoneyChange();
}
}
public string Name { get; set; }
public Stock(int money, string name)
{
Name = name;
_money = money;
}
private void OnMoneyChange()
{
Message message = new Message();
message.Money = Money;
message.StockName = Name;
TradingSystem.GetInstance.Notify(message);
}
}
}
Program类:
using Observer.Observer.Example;
using Observer.Observer.Question6;
namespace Observer
{
internal class Program
{
public static void Main()
{
XiaoHong xiaoHong = new XiaoHong("xiaohong");
XiaoMing xiaoMing = new XiaoMing("xiaoming");
Stock beijingStock = new BeiJingStock(100,"beijing");
Stock shanghaiStock = new ShangHaiStock(200, "shanghai");
TradingSystem.GetInstance.Add(beijingStock.Name, xiaoHong);
TradingSystem.GetInstance.Add(beijingStock.Name, xiaoMing);
beijingStock.Money = 200;
}
}
}
观察者模式总结
观察者模式的优点:
- 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制。
- 观察者模式支持广播通讯,观察目标会向所有已注册的观察者对象发送通知,简化一对多的系统设计难度。
观察者模式的缺点:
- 如果一个观察目标对象有许多直接间接观察者,将所有的观察者都通知到需要花费时间。
- 观察者和观察对象之间可能会存在循环依赖,一旦触发,可能导致系统崩溃。