目录
- 定义
- 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