觀察者模式定義了一個一對多的對象關系:一個主體對象對應多個觀察者對象。當主體對象發生改變時,所有它對應的觀察者對象都會自動得到通知並更新。
本文將給出一個相應的事例具體說明觀察者模式是如果工作的。這個事例演示了一個當一個任務的信息改變時通知這個任務所涉及所有人員的事例。任務信息包括任務狀態,任務所采用的處理流程和任務完成後的checklist[用來確保任務完成所有預定需要完成的功能列表和避免一些常見的錯誤]。
先定義兩個接口:主體對象接口和觀察者對象接口。
/** *//**
* 主體對象接口定義了注冊觀察者,取消觀察者和通知觀察者方法。
*
*/
public interface ISubject {
/** *//**
* 為該主體對象注冊一個觀察者。
*/
public void registerObserver(IObserver observer);
/** *//**
* 從該主體對象中取消一個觀察者的注冊。
*/
public void removeObserver(IObserver observer);
/** *//**
* 通知所有觀察者。
*/
public void notifyObserver();
}
/** *//**
* 觀察者接口簡單定義了一個用來更新觀察者信息的接口。
* 當主體對象被更新時,這個接口方法會被自動調用並更新信息。
*/
public interface IObserver {
/** *//**
* 接口方法用來更新觀察者的信息。
*/
public void remind(ITask taskSubject);
}
這兩個接口只定義了主題對象和觀察者對象所需要的接口,但是沒有實現任何任務相關的具體的方法和接口。下面會再定義一個任務接口來規定任務應該具備的功能。這樣分開定義的好處在於,如果我們將不同的模塊分解開來,如果一方需要更新,另一方不會受到影響。
/** *//**
* 這裡定義了一個任務應該具有的功能。
*/
public interface ITask {
public void setStatus(String status);
public String getStatus();
public void setProcess(String process);
public String getProcess();
public void setCheckList(String checkList);
public String getCheckList();
}
然後我們創建具體的任務主體。這裡我們會實現ISubejct, ITask兩個接口。
import java.util.ArrayList;
import java.util.List;
public class TaskSubject implements ISubject, ITask {
// 在這裡對觀察者列表進行初始化。因為是靜態初始化,所以保證在這個運行過程中只有一個實例得到初始化。
static {
_observers = new ArrayList<IObserver>();
}
@Override
public void notifyObserver() {
// 調用觀察者的方法通知並更新觀察者信息。
for(IObserver observer : _observers) {
observer.remind(this);
}
}
@Override
public void registerObserver(IObserver observer) {
if(_observers.contains(observer)) {
System.out.println("< " + observer + " > is already registed!");
}
// Register an observer
_observers.add(observer);
System.out.println("< " + observer + " > is registed successfully!");
}
@Override
public void removeObserver(IObserver observer) {
if(!_observers.contains(observer)) {
System.out.println("< " + observer + " > is never registed!");
}
// Remove an observer
_observers.remove(observer);
System.out.println("< " + observer + " > is removed successfully!");
}
@Override
public String getCheckList() {
return this._checkList;
}
@Override
public String getProcess() {
return this._process;
}
@Override
public String getStatus() {
return this._status;
}
@Override
public void setCheckList(String checkList) {
this._checkList = checkList;
}
@Override
public void setProcess(String process) {
this._process = process;
}
@Override
public void setStatus(String status) {
this._status = status;
}
// 這裡將觀察者列表定義為一個靜態的變量,這樣可以保證自始至終只有一個變量列表,便於系統的維護。
// 這裡用到了泛型,這樣在對這個列表進行操作的時候,無需再進行類型的轉換。
private static List<IObserver> _observers;
private String _status;
private String _process;
private String _checkList;
}
在這裡我們沒有給觀察者定義接口,而是使用了一個抽象類。因為所有的觀察者都必須從主體對象那裡獲取信息,而且獲取信息的方法都是一樣的,這樣可以避免重復編碼。
/** *//**
* 這個抽象類繼承了Iobserver接口,所以我們必須實現remind方法。
* 在remind方法中從主體對象中獲取所有需要的信息。
* 並調用sendEmail方法對觀察者實時進行更新。
*/
public abstract class TaskObserver implements IObserver {
@Override
public void remind(ITask taskSubject) {
this._status = taskSubject.getStatus();
this._process = taskSubject.getProcess();
this._checkList = taskSubject.getCheckList();
// 更新觀察者對象
this.sendEmail();
}
public abstract void sendEmail();
// 工具類方法,減少編碼數量,增加可讀性。
public void print(String msg) {
System.out.println(msg);
}
// 在父類中定義參數,減少重復編碼。
protected String _status;
protected String _process;
protected String _checkList;
}
然後定義任務受托人[assignee],檢查者,報告者。他們都繼承TaskObserver類,這樣減少了代碼的重復,而且方便了代碼的維護。
public class Assignee extends TaskObserver {
@Override
public void sendEmail() {
print("[Assignee] The current status is : <" + this._status + ">.");
print("[Assignee] The current process is : <" + this._process + ">.");
print("[Assignee] The current checklist is : <" + this._checkList + ">.");
}
public String toString() {
return "Assignee";
}
}
public class Reviewer extends TaskObserver {
@Override
public void sendEmail() {
print("[Reviewer] The current status is : <" + this._status + ">.");
print("[Reviewer] The current process is : <" + this._process + ">.");
print("[Reviewer] The current checklist is : <" + this._checkList + ">.");
}
public String toString() {
return "Reviewer";
}
}
public class Reporter extends TaskObserver {
@Override
public void sendEmail() {
print("[Reporter] The current status is : <" + this._status + ">.");
print("[Reporter] The current process is : <" + this._process + ">.");
print("[Reporter] The current checklist is : <" + this._checkList + ">.");
}
public String toString() {
return "Reporter";
}
}
然後我們需要編寫一個類用來演示觀察者模式,在這個類中會演示注冊觀察者,取消特定觀察者,更改主體對象信息然後觀察者自動得到通知並更新信息。
public class TaskManager {
public static void main(String[] args) {
// Create subject
TaskSubject taskSubject = new TaskSubject();
// Create observers
IObserver assignee = new Assignee();
IObserver reviewer = new Reviewer();
IObserver reporter = new Reporter();
// 注冊觀察者[因為我們使用的是一個列表,所以在通知觀察者的時候是按照添加的順序通知的]
taskSubject.registerObserver(assignee);
taskSubject.registerObserver(reviewer);
taskSubject.registerObserver(reporter);
// 更新主體對象的信息
taskSubject.setStatus("Assigned");
taskSubject.setProcess("No Process Attacted");
taskSubject.setCheckList("CheckList Version 1.0");
// 通知所有觀察者
taskSubject.notifyObserver();
// 更新主體對象信息
taskSubject.setStatus("In Progress");
taskSubject.setProcess("Process Attached");
taskSubject.setCheckList("CheckList Version Final Version");
// 取消報告者的注冊,並通知剩余所有觀察者
taskSubject.removeObserver(reporter);
taskSubject.notifyObserver();
}
}
輸出的信息如下:
< Assignee > is registed successfully!
< Reviewer > is registed successfully!
< Reporter > is registed successfully!
[Assignee] The current status is : <Assigned>.
[Assignee] The current process is : <No Process Attacted>.
[Assignee] The current checklist is : <CheckList Version 1.0>.
[Reviewer] The current status is : <Assigned>.
[Reviewer] The current process is : <No Process Attacted>.
[Reviewer] The current checklist is : <CheckList Version 1.0>.
[Reporter] The current status is : <Assigned>.
[Reporter] The current process is : <No Process Attacted>.
[Reporter] The current checklist is : <CheckList Version 1.0>.
< Reporter > is removed successfully!
[Assignee] The current status is : <In Progress>.
[Assignee] The current process is : <Process Attached>.
[Assignee] The current checklist is : <CheckList Version Final Version>.
[Reviewer] The current status is : <In Progress>.
[Reviewer] The current process is : <Process Attached>.
[Reviewer] The current checklist is : <CheckList Version Final Version>.