2009年7月25日 星期六

Design Pattern - Observer

Observer 觀察者模式

假設有個需求

提供一個佈告欄, 分別提供 blog與forum頻道的資訊
1.希望會自動更新所有佈告欄
2.要容易增加新的佈告欄

或許我們可以這樣寫


//當資料有更新時
public class BulletinData{

public void update(){

String title = getTitle(); --> 也許直接去db撈, 或者call api
String content = getContent();

BulletinBlog.update(title, content);
BulletinForum.update(title, content);

}
}

public class BulletinBlog{
public void update();
public void display();
}

public class BulletinForum{
public void update();
}


觀察者模式就是 主題與觀察者一對多的關係
以出版社為例
出版者 + 訂閱者 = Observer模式

subject <-- 1 對多 --> observer

或許可以這樣寫

public interface ISubject{
public void registerObserver(IObserver o);
public void removeObserver(IObserver o);
public void notifyObserver();
}

public interface IObserver{
//這裡把這些field值寫死了, 不好
public void update(String title, String content);
}

public interface IDisplay{
public void display();
}

//資料來源的BulletinData當作subject
public class BulletinData implements ISubject{

private List lobserver;
private String title;
private String content;

public BulletinData(){
lobserver = new ArrayList();
}

public void registerObserver(IObserver o){
lobserver.add(o);
}

public void removeObserver(IObserver o){
lobserver.remove(o);
}

public void notifyObserver(){
for (int i = 0; i < lobserver.size(); i++) {
Observer observer = (Observer)lobserver.get(i);
observer.update(this.title, this.content);
}
}

public void update(){
notifyObserver();
}

public void setNewData(String title, String content){
this.title = title;
this.content = content;
this.update();
}
}

public class BulletinBlog implements IObserver, IDisplay{
private String title;
private String content;
private ISubject bulletinData;

public BulletinBlog(ISubject BulletinData){
this.bulletinData = bulletinData;
BulletinData.registerObserver(this); --> 註冊成為觀察者
}

public void update(String title, String content){
this.title = title;
this.content = content;
display();
}

public void display(){}
}

public class BulletinForum implements IObserver, IDisplay{
...
}

public class Demo {
public static void main(String[] args) {

BulletinData bulletinData = new BulletinData();

BulletinBlog bulletinBlog = new BulletinBlog(bulletinData);
BulletinForum bulletinForum= new BulletinForum(bulletinData);

//當資料有更新時, 也許直接去db撈, 或者call api
String title = "new title";
String content = "new content";
bulletinData.update(title, content); --> 會通知所有有註冊的觀察者了
}
}


subject依賴的是一個observer的interface, 所以subject不用管有多少class去implements
以上的作法,

java.util 有提供Observer模式
java.util.Observer 這是interface, 讓我們implents觀察者
java.util.Observable 可以去extends Observable class, 再去增加取得新資料的方法

上方的例子, 主動權是在subject, 都是由subject去把資料推給觀察者,
而java.util提供的Observer可以做到由觀察者自己去拉資料

下方的code是由java.util提供方式來實作
head first design pattern一書copy貼上的, 請參考用



import java.util.Observable;
import java.util.Observer;

public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;

public WeatherData() { }

public void measurementsChanged() {
setChanged();
notifyObservers();
}

public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}

public float getTemperature() {
return temperature;
}

public float getHumidity() {
return humidity;
}

public float getPressure() {
return pressure;
}
}

import java.util.Observable;
import java.util.Observer;

public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}

public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}

public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}




名言??
松耦合 --> 當二個object可以交互, 但又不清楚彼此的細節

0 意見: