|
Design Pattern - Observer
|
| (史帝芬, 2003/10/26, hi.steven@gmail.com) |
Observer的目的在於定義一對多的物件依存關係,讓物件狀態一有變動,就自動通知其他相依物件做該做的更
新動作,這個Pattern可以說是MVC的基礎架構。我自己第一次使用它是用在電子郵件認證,當系統收到使用者
回覆的email時,通知所有相關物件處理後續事項; 第二次使用是在電腦象棋中,當電腦決定出下一著手時,通
知棋盤、棋著列表和歷史棋著儲存區更新狀態。這是個常有機會用到的Pattern,學會了一定會受益良多。在
Observer裡的update是NumberGenerator用來通知Observer,內容已被更新的method。
底下分別以C++、Java、C#來實作,各位網友可以看到同一個pattern在不同語言間仍會有些差異。
NumberGenerator.h
#ifndef __NUMBER_GENERATOR_H
#define __NUMBER_GENERATOR_H
#include <set>
#if _MSC_VER > 1020 // if VC++ version is > 4.2
using namespace std; // std c++ libs implemented in std
#endif
#include "Observer.h"
typedef set<Observer*> SET;
class NumberGenerator {
private:
SET _observers;
public:
virtual void attach(Observer*);
virtual void detach(Observer*);
void notify();
virtual void setState(int n) = 0;
virtual int getState() = 0;
};
#endif
NumberGenerator.cpp
#include "NumberGenerator.h"
#include "Observer.h"
void NumberGenerator::attach(Observer* o)
{
_observers.insert(o);
}
void NumberGenerator::detach(Observer* o)
{
_observers.erase(o);
}
void NumberGenerator::notify()
{
SET::iterator i;
for(i = _observers.begin(); i != _observers.end(); i++) {
((Observer*)(*i))->update(this);
}
}
Observer.h
#ifndef __OBSERVER_H
#define __OBSERVER_H
class NumberGenerator;
class Observer {
public:
virtual void update(NumberGenerator* n) = 0;
};
#endif
RandomNumberGenerator.h
#ifndef __RANDOM_NUMBER_GENERATOR_H
#define __RANDOM_NUMBER_GENERATOR_H
#include "NumberGenerator.h"
class RandomNumberGenerator: public NumberGenerator {
private:
int state;
public:
int getState();
void setState(int s);
};
#endif
RandomNumberGenerator.cpp
#include "RandomNumberGenerator.h"
int RandomNumberGenerator::getState()
{
return state;
}
void RandomNumberGenerator::setState(int s)
{
state = s;
notify();
}
DigitObserver.h
#ifndef DIGIT_H
#define DIGIT_H
#include "Observer.h"
class NumberGenerator;
class DigitObserver: public Observer {
public:
void update(NumberGenerator* n);
};
#endif
DigitObserver.cpp
#include "DigitObserver.h"
#include "NumberGenerator.h"
#include <iostream>
void DigitObserver::update(NumberGenerator* n)
{
cout << "state: " << n->getState() << endl;
}
GraphObserver.cpp
#ifndef GRAPH_H
#define GRAPH_H
#include "Observer.h"
class NumberGenerator;
class GraphObserver: public Observer {
public:
void update(NumberGenerator* n);
};
#endif
測試程式
#include "RandomNumberGenerator.h"
#include "DigitObserver.h"
#include "GraphObserver.h"
void main()
{
NumberGenerator* gen = new RandomNumberGenerator();
Observer* ob1 = new DigitObserver();
Observer* ob2 = new GraphObserver();
gen->attach(ob1);
gen->attach(ob2);
gen->setState(5);
}
執行結果 state: 5 state: ##### 說明: 在class NumberGenerator裡用到的set是STL。 NumberGenerator.java
import java.util.Vector;
import java.util.Iterator;
public abstract class NumberGenerator {
private Vector observers = new Vector();
public void attach(Observer o) {
observers.add(o);
}
public void detach(Observer o) {
observers.remove(o);
}
public void Notify() {
for(Iterator it = observers.iterator(); it.hasNext(); ) {
Observer o = (Observer) it.next();
o.update(this);
}
}
public abstract int getState();
public abstract void setState(int n);
}
Observer.java
public interface Observer {
public void update(NumberGenerator n);
}
RandomNumberGenerator.java
public class RandomNumberGenerator extends NumberGenerator {
private int count = 0;
public int getState() {
return count;
}
public void setState(int n) {
count = n;
Notify();
}
}
DigitObserver.java
public class DigitObserver implements Observer {
public void update(NumberGenerator n) {
int count = n.getState();
System.out.println("state => " + count);
}
}
GraphObserver.java
public class GraphObserver implements Observer {
public void update(NumberGenerator n) {
int count = n.getState();
System.out.print("state => ");
for(int i=0; i < count; i++) {
System.out.print("#");
}
System.out.println("");
}
}
測試程式
NumberGenerator gen = new RandomNumberGenerator(); Observer ob1 = new DigitObserver(); Observer ob2 = new GraphObserver(); gen.attach(ob1); gen.attach(ob2); gen.setState(6);執行結果 state => 6 state => ###### C++及Java透過interface達到委託的目的,C#直接在語言中提供了delegate,在實現 observer pattern時更簡單方便。這兩種方法的差別最明顯有兩個: 1. 透過interface,委託的標的物是class,透過delegate時,標的物為method。 2. C#透過運算子的多載,使得委託函式的新增、移除更簡單。
using System;
namespace ObserverPattern
{
public class NumberGenerator
{
public delegate void Observer(int n);
private Observer observer;
public void attach(Observer o)
{
observer += o;
}
public void detach(Observer o)
{
observer -= o;
}
public void update(int n)
{
observer(n);
}
}
class Program
{
public void DigitObserver(int n)
{
Console.WriteLine("State: " + n);
}
public void GraphObserver(int n)
{
Console.Write("State: ");
for (int i = 0; i < n; i++)
{
Console.Write("#");
}
Console.WriteLine();
}
static void Main(string[] args)
{
Program pgm = new Program();
NumberGenerator num = new NumberGenerator();
num.attach(pgm.DigitObserver);
num.attach(pgm.GraphObserver);
num.update(10);
Console.ReadLine();
}
}
}
執行結果State: 10 State: ########## |