c#-设计模式之观察者模式
概念
指多个对象之间存在一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。该模式又称为包括发布-订阅(Publish/Subscribe)模式,该模式是行为型模式。
结构图
角色
-
Subject(观察目标):观察目标是指被观察的对象,一般由抽象类或接口实现,观察目标把所有观察者对象的引用保存在一个列表中,并提供增加和删除观察者对象的操作,同时它定义了通知方法notify()。
-
ConcreteSubject(具体观察目标):具体观察目标,实现观察目标,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
-
Observer(观察者):为所有具体观察者定义一个接口,观察者将对观察目标的改变做出反应。
-
ConcreteObserver(具体观察者):实现观察目标所要求的接口,以便使自身状态与主题的状态相协调。
优点
-
降低了目标与观察者之间的耦合关系,观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
-
观察者模式支持“广播通信”。主题会向所有的观察者发出通知。
-
观察者模式符合“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
缺点
-
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
-
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
-
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景
-
当一个对象的改变需要同时改变其它对象时,而且不必知道具体有多少对象要改变。
-
完成某件事情后,异步通知的场景,例如用户注册(发短信、电子邮件)、用户登录(发送IM消息)。
代码实现
-
当股票购买者所购买的股票价格发生变化的时候,系统将自动发送通知给购买该股票的所有股民。
此场景中,股民为观察者,股票为被观察者。
观察者接口
public interface IObserver { void Update(Stock stock); }
具体观察者:股民
public class Investor : IObserver { private string name; public Investor(string name) { this.name = name; } public void Update(Stock stock) { Console.WriteLine($"通知股民{name}: {stock.GetSymbol()}股票的价格变更为{stock.GetPrice()}"); } }
主题接口
public interface ISubject { void RegisterObserver(IObserver observer); void RemoveObserver(IObserver observer); void NotifyObservers(); }
具体的主题:股票
public class Stock : ISubject { private List<IObserver> observers; private string symbol; private double price; public Stock(string symbol, double price) { this.symbol = symbol; this.price = price; this.observers = new List<IObserver>(); } public void RegisterObserver(IObserver observer) { observers.Add(observer); } public void RemoveObserver(IObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (var observer in observers) { observer.Update(this); } } public string GetSymbol() { return symbol; } public double GetPrice() { return price; } public void SetPrice(double price) { this.price = price; NotifyObservers(); } }
客户端
static void Main(string[] args) { Stock stock = new Stock("A股", 120); Investor investor1 = new Investor("张三"); Investor investor2 = new Investor("李四"); stock.RegisterObserver(investor1); stock.RegisterObserver(investor2); stock.SetPrice(125); stock.SetPrice(115); stock.RemoveObserver(investor1); stock.SetPrice(130.0); Console.ReadLine(); }
运行截图
-
猫进屋了,老鼠都走了。
此场景中,老鼠为观察者,猫为被观察者。
猫
public class Cat { private string color; private string name; public Cat(string color,string name) { this.color = color; this.name = name; } /// <summary> /// 定义事件 /// </summary> public event Action CatCome; public void CatComing() { Console.WriteLine(color + "的猫:" + name + "进屋了。"); if(CatCome!=null) { CatCome(); } } }
老鼠
public class Mouse
{
private string color;
private string name;
public Mouse(string color, string name,Cat cat)
{
this.color = color;
this.name = name;
cat.CatCome += this.Run;
}
public void Run()
{
Console.WriteLine(color + "的" + name + "说猫来了,赶紧跑!!!");
}
}
客户端
static void Main(string[] args)
{
Cat cat1 = new Cat("黄色", "加菲");
Mouse mouse1 = new Mouse("黑色", "米奇", cat1);
Mouse mouse2 = new Mouse("黑色", "杰克", cat1);
Mouse mouse3 = new Mouse("黑色", "杰瑞", cat1);
cat1.CatComing();
}
运行截图