目錄
- 定義
- 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