一、问题产生背景
又被称为订阅发布模式。
最初流传最广的一个面试题:有一只猫咪,猫咪叫了一声,老鼠跑了,老人惊醒了,男主人骂,小偷吓得不敢动了....这就产生一个问题的模型,当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
二、观察者模式的通常做法
1、 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2、 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4、具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
结构图:
三、具体实例
观察者模式的实现方式有几种,下面我们用接口方式实现。
1、首先我们建立观察者的抽象
namespace ObserverPattern { public interface IObserver { void update(string message); } }
2、建立被观察者的抽象
namespace ObserverPattern { public interface ISubject { void Attach(IObserver observer ); void Detach(IObserver observer); void Notify(string message); } }
3、观察者实例化
namespace ObserverPattern { public class User:IObserver { private string _name; public User(string name) { _name = name; } public void update(string message) { Console.WriteLine("hi"+_name+","+message); } } }
4、被观察者实例化(注意其中的观察者列表)
namespace ObserverPattern { public class SubscriptionSubject:ISubject { private List<IObserver> userList = new List<IObserver>(); public void Attach(IObserver observer) { userList.Add(observer); } public void Detach(IObserver observer) { userList.Remove(observer); } public void Notify(String message) { foreach (IObserver observer in userList) { observer.update(message); } } } }
5、我们整盒调用
namespace ObserverPattern { class Program { static void Main(string[] args) { SubscriptionSubject mSubscriptionSubject = new SubscriptionSubject(); //创建用户 User user1 = new User("林熙蕾"); User user2 = new User("潘春春"); User user3 = new User("罗云绮"); //订阅微博 mSubscriptionSubject.Attach(user1); mSubscriptionSubject.Attach(user2); mSubscriptionSubject.Attach(user3); //博主发通知 mSubscriptionSubject.Notify("刘德华发微博了"); Console.ReadKey(); } } }
四、设计模式分析
优点:
支持广播通信。
聚耦合,所有的观察者被抽象为一个接口。
缺点:
时间较长。
内联不足,具体表现在,观察者不能明确知道被观察者如何变化
可能出现循环调用