
//
Observer pattern -- Structural example

using
System;

using
System.Collections;


//
"Subject"

abstract
class
Subject

{

// Fields

private ArrayList observers = new ArrayList();


// Methods

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();

}

}


//
"ConcreteSubject"

class
ConcreteSubject : Subject

{

// Fields

private string subjectState;


// Properties

public string SubjectState

{

get{ return subjectState; }

set{ subjectState = value; }

}

}


//
"Observer"

abstract
class
Observer

{

// Methods

abstract public void Update();

}


//
"ConcreteObserver"

class
ConcreteObserver : Observer

{

// Fields

private string name;

private string observerState;

private ConcreteSubject subject;


// Constructors

public ConcreteObserver( ConcreteSubject subject,

string name )

{

this.subject = subject;

this.name = name;

}


// Methods

override public void Update()

{

observerState = subject.SubjectState;

Console.WriteLine( "Observer {0}'s new state is {1}",

name, observerState );

}


// Properties

public ConcreteSubject Subject

{

get { return subject; }

set { subject = value; }

}

}


/// <summary>

/// Client test

/// </summary>

public
class
Client

{

public static void Main( string[] args )

{

// Configure Observer structure

ConcreteSubject s = new ConcreteSubject();

s.Attach( new ConcreteObserver( s, "1" ) );

s.Attach( new ConcreteObserver( s, "2" ) );

s.Attach( new ConcreteObserver( s, "3" ) );


// Change subject and notify observers

s.SubjectState = "ABC";

s.Notify();

}

}
四、 C#中的Delegate与Event
实际上在C#中实现Observer模式没有这么辛苦,.NET中提供了Delegate与Event机制,我们可以利用这种机制简化Observer模式。关于Delegate与Event的使用方法请参考相关文档。改进后的Observer模式实现如下:

//
Observer pattern -- Structural example

using
System;


//
Delegate

delegate
void
UpdateDelegate();


//
Subject

class
Subject

{

public event UpdateDelegate UpdateHandler;

// Methods

public void Attach( UpdateDelegate ud )

{

UpdateHandler += ud;

}


public void Detach( UpdateDelegate ud )

{

UpdateHandler -= ud;

}

public void Notify()

{

if(UpdateHandler != null) UpdateHandler();

}


}


//
ConcreteSubject

class
ConcreteSubject : Subject

{

// Fields

private string subjectState;


// Properties

public string SubjectState

{

get{ return subjectState; }

set{ subjectState = value; }

}

}


//
"ConcreteObserver"

class
ConcreteObserver

{

// Fields

private string name;

private string observerState;

private ConcreteSubject subject;


// Constructors

public ConcreteObserver( ConcreteSubject subject,

string name )

{

this.subject = subject;

this.name = name;

}


// Methods

public void Update()

{

observerState = subject.SubjectState;

Console.WriteLine( "Observer {0}'s new state is {1}",

name, observerState );

}


// Properties

public ConcreteSubject Subject

{

get { return subject; }

set { subject = value; }

}

}


//
"ConcreteObserver"

class
AnotherObserver

{

// Methods

public void Show()

{

Console.WriteLine("AnotherObserver got an Notification!");

}

}


public
class
Client

{

public static void Main(string[] args)

{

ConcreteSubject s = new ConcreteSubject();

ConcreteObserver o1 = new ConcreteObserver(s, "1");

ConcreteObserver o2 = new ConcreteObserver(s, "2");

AnotherObserver o3 = new AnotherObserver();

s.Attach(new UpdateDelegate(o1.Update));

s.Attach(new UpdateDelegate(o2.Update));

s.Attach(new UpdateDelegate(o3.Show));


s.SubjectState = "ABC";

s.Notify();


Console.WriteLine("--------------------------");

s.Detach(new UpdateDelegate(o1.Update));


s.SubjectState = "DEF";

s.Notify();

}

}
其中,关键的代码如下:

delegate
void
UpdateDelegate();
定义一个Delegate,用来规范函数结构。不管是ConcreteObserver类的Update方法还是AnotherObserver类的Show方法都符合该Delegate。这不象用Observer接口来规范必须使用Update方法那么严格。只要符合Delegate所指定的方法结构的方法都可以在后面被事件所处理。

public
event
UpdateDelegate UpdateHandler;
定义一个事件,一旦触发,可以调用一组符合UpdateDelegate规范的方法。

public
void
Attach( UpdateDelegate ud )

{

UpdateHandler += ud;

}
订阅事件。只要是一个满足UpdateDelegate的方法,就可以进行订阅操作(如下所示)。

s.Attach(
new
UpdateDelegate(o1.Update));

s.Attach(
new
UpdateDelegate(o2.Update));

s.Attach(
new
UpdateDelegate(o3.Show));
在Notify方法中:

public
void
Notify()

{

if(UpdateHandler != null) UpdateHandler();

}
只要UpdateHandler != null(表示有订阅者),就可以触发事件(UpdateHandler()),所有的订阅者便会接到通知。
五、 一个实际应用观察者模式的例子
该例子演示了注册的投资者在股票市场发生变化时,可以自动得到通知。该例子仍然使用的是传统的Observer处理手段,至于如何转换成Delegate与Event留给读者自己考虑。

//
Observer pattern -- Real World example

using
System;

using
System.Collections;


//
"Subject"

abstract
class
Stock

{

// Fields

protected string symbol;

protected double price;

private ArrayList investors = new ArrayList();


// Constructor

public Stock( string symbol, double price )

{

this.symbol = symbol;

this.price = price;

}


// Methods

public void Attach( Investor investor )

{

investors.Add( investor );

}


public void Detach( Investor investor )

{

investors.Remove( investor );

}


public void Notify()

{

foreach( Investor i in investors )

i.Update( this );

}


// Properties

public double Price

{

get{ return price; }

set

{

price = value;

Notify();

}

}


public string Symbol

{

get{ return symbol; }

set{ symbol = value; }

}

}


//
"ConcreteSubject"

class
IBM : Stock

{

// Constructor

public IBM( string symbol, double price )

: base( symbol, price ) {}

}


//
"Observer"

interface
IInvestor

{

// Methods

void Update( Stock stock );

}


//
"ConcreteObserver"

class
Investor : IInvestor

{

// Fields

private string name;

private string observerState;

private Stock stock;


// Constructors

public Investor( string name )

{

this.name = name;

}


// Methods

public void Update( Stock stock )

{

Console.WriteLine( "Notified investor {0} of {1}'s change to {2:C}",

name, stock.Symbol, stock.Price );

}


// Properties

public Stock Stock

{

get{ return stock; }

set{ stock = value; }

}

}


/// <summary>

/// ObserverApp test

/// </summary>

public
class
ObserverApp

{

public static void Main( string[] args )

{

// Create investors

Investor s = new Investor( "Sorros" );

Investor b = new Investor( "Berkshire" );


// Create IBM stock and attach investors

IBM ibm = new IBM( "IBM", 120.00 );

ibm.Attach( s );

ibm.Attach( b );


// Change price, which notifies investors

ibm.Price = 120.10;

ibm.Price = 121.00;

ibm.Price = 120.50;

ibm.Price = 120.75;

}

}
六、 观察者模式的优缺点
Observer模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样不同的表示层(观察者)。
但是其缺点是每个外观对象必须继承这个抽像出来的接口类,这样就造成了一些不方便,比如有一个别人写的外观对象,并没有继承该抽象类,或者接口不对,我们又希望不修改该类直接使用它。虽然可以再应用Adapter模式来一定程度上解决这个问题,但是会造成更加复杂烦琐的设计,增加出错几率。
观察者模式的效果有以下几个优点:
(1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
(2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的一些缺点:
(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社