目录
- 定义
- UML
- 参与者
- 示例
定义:
定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
UML:
参与者:
主题(Subject)角色:
主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做被观察者(Observable)角色。
具体主题(ConcreteSubject)角色:
实现主题这个角色接口的具体类,将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。
观察者(Observer)角色:
为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
具体观察者(ConcreteObserver)角色:
具体现察者角色实现观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
示例:
代码using System; using System.Collections.Generic; namespace DoFactory.GangOfFour.Observer.Structural { /// <summary> /// MainApp startup class for Structural /// Observer Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main() { // Configure Observer pattern ConcreteSubject s = new ConcreteSubject(); s.Attach(new ConcreteObserver(s, "X")); s.Attach(new ConcreteObserver(s, "Y")); s.Attach(new ConcreteObserver(s, "Z")); // Change subject and notify observers s.SubjectState = "ABC"; s.Notify(); // Wait for user Console.ReadKey(); } } /// <summary> /// The 'Subject' abstract class /// </summary> abstract class Subject { private List<Observer> _observers = new List<Observer>(); public void Attach(Observer observer) { _observers.Add(observer); } public void Detach(Observer observer) { _observers.Remove(observer); } public void Notify() { foreach (Observer o in _observers) { o.Update(); } } } /// <summary> /// The 'ConcreteSubject' class /// </summary> class ConcreteSubject : Subject { private string _subjectState; // Gets or sets subject state public string SubjectState { get { return _subjectState; } set { _subjectState = value; } } } /// <summary> /// The 'Observer' abstract class /// </summary> abstract class Observer { public abstract void Update(); } /// <summary> /// The 'ConcreteObserver' class /// </summary> class ConcreteObserver : Observer { private string _name; private string _observerState; private ConcreteSubject _subject; // Constructor public ConcreteObserver( ConcreteSubject subject, string name) { this._subject = subject; this._name = name; } public override void Update() { _observerState = _subject.SubjectState; Console.WriteLine("Observer {0}'s new state is {1}", _name, _observerState); } // Gets or sets subject public ConcreteSubject Subject { get { return _subject; } set { _subject = value; } } } }
output
Observer X's new state is ABC
Observer Y's new state is ABC
Observer Z's new state is ABC
实际运用
代码using System; using System.Collections.Generic; namespace DoFactory.GangOfFour.Observer.RealWorld { /// <summary> /// MainApp startup class for Real-World /// Observer Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main() { // Create IBM stock and attach investors IBM ibm = new IBM("IBM", 120.00); ibm.Attach(new Investor("Sorros")); ibm.Attach(new Investor("Berkshire")); // Fluctuating prices will notify investors ibm.Price = 120.10; ibm.Price = 121.00; ibm.Price = 120.50; ibm.Price = 120.75; // Wait for user Console.ReadKey(); } } /// <summary> /// The 'Subject' abstract class /// </summary> abstract class Stock { private string _symbol; private double _price; private List<IInvestor> _investors = new List<IInvestor>(); // Constructor public Stock(string symbol, double price) { this._symbol = symbol; this._price = price; } public void Attach(IInvestor investor) { _investors.Add(investor); } public void Detach(IInvestor investor) { _investors.Remove(investor); } public void Notify() { foreach (IInvestor investor in _investors) { investor.Update(this); } Console.WriteLine(""); } // Gets or sets the price public double Price { get { return _price; } set { if (_price != value) { _price = value; Notify(); } } } // Gets the symbol public string Symbol { get { return _symbol; } } } /// <summary> /// The 'ConcreteSubject' class /// </summary> class IBM : Stock { // Constructor public IBM(string symbol, double price) : base(symbol, price) { } } /// <summary> /// The 'Observer' interface /// </summary> interface IInvestor { void Update(Stock stock); } /// <summary> /// The 'ConcreteObserver' class /// </summary> class Investor : IInvestor { private string _name; private Stock _stock; // Constructor public Investor(string name) { this._name = name; } public void Update(Stock stock) { Console.WriteLine("Notified {0} of {1}'s " + "change to {2:C}", _name, stock.Symbol, stock.Price); } // Gets or sets the stock public Stock Stock { get { return _stock; } set { _stock = value; } } } }
Output
Notified Sorros of IBM's change to $120.10
Notified Berkshire of IBM's change to $120.10
Notified Sorros of IBM's change to $121.00
Notified Berkshire of IBM's change to $121.00
Notified Sorros of IBM's change to $120.50
Notified Berkshire of IBM's change to $120.50
Notified Sorros of IBM's change to $120.75
Notified Berkshire of IBM's change to $120.75