在生活實際中,我們經常會遇到關注一個事物數據變化的情況,例如生活中的溫度記錄儀,當溫度變化時,我們觀察它溫度變化的曲線,溫度記錄日志等。對於這一類問題,很接近java設計模式里面的“觀察者模式”,它適合解決多種對象跟蹤一個對象數據變化的程序結構問題。
觀察者設計模式涉及到兩種角色:主題(Subject)和觀察者(Observer)
下面以java JDK中已有的觀察者設計模式代碼,展示使用:
1.主題(Subject):Observable類派生出來的子類,只需要定義各被監控的數據及getter()、setter()方法,getter方法主要用於具體觀察者“拉”數據,setter方法主要用於更新、設置changed變量及通知各具體觀察者進行數據響應。代碼如下:
import java.util.Observable; public class Subject extends Observable{ private String data; public String getData() { return data; } public void setData(String data) { //更新數據 this.data = data; //置更新數據標志 setChanged(); //通知各個具體的觀察者,這里有推數據的作用 notifyObservers(null); } }
2.觀察者(Observer):編寫具體的觀察者類實現觀察者接口,通過參數傳遞主題對象獲取更新的數據。update()方法主要用於“拉”數據及處理過程。代碼如下:
import java.util.Observable; import java.util.Observer; public class ObserverOne implements Observer{ @Override public void update(Observable o, Object arg) { // TODO Auto-generated method stub Subject subject = (Subject) o; System.out.println("數據正在更新為:"+subject.getData()); } }
下面寫一個簡單的測試類來測試一下:
import java.util.Observer; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub Observer obj = new ObserverOne(); Subject subject = new Subject(); subject.addObserver(obj); subject.setData("One"); } }
輸出結果:“數據正在更新為:One”
由java JDK實現的觀察者模式來看,當在使用時感覺代碼很簡單,其實去看Observerable類和Observer接口的源碼就知道,這些都是專家級的代碼,學習了觀察者模式后,下面得出一些結論:
1)主題要知道哪些觀察者對其進行監測,說明主題類中一定有一個集合類成員變量,添加和刪除及判斷這些觀察者對象是否存在。
2)觀察者類一定是多態的,有共同的父類接口。
3)主題完成的功能基本是固定的,添加觀察者、撤銷觀察者、通知消息給觀察者及引起觀察者響應(即“拉”數據),可以抽象出來。
經過以上的思考和總結,下面是自定義形式寫的觀察者模式:
1.編寫觀察者接口(IObserver)。代碼如下:
public interface IObserver{ //傳入的參數對象可以間接獲取變化后的主題數據 public void refresh(ISubject subject); }
2.編寫主題接口(ISubject)。代碼如下:
public interface ISubject{ //注冊觀察者 public void register(IObserver obs); //撤銷觀察者 public void unregister(IObserver obs); //通知所有觀察者及進行數據響應 public void notifyObservers(); }
3.增加主題抽象類層(AbstractSubject)。代碼如下:
import java.util.ArrayList; public class AbstractSubject implements ISubject{ private ArrayList<IObserver> array = new ArrayList<IObserver>(); @Override public void register(IObserver obs) { // TODO Auto-generated method stub array.add(obs); } @Override public void unregister(IObserver obs) { // TODO Auto-generated method stub array.remove(obs); } @Override public void notifyObservers() { // TODO Auto-generated method stub for(int i=0;i<array.size();i++){ IObserver obs = array.get(i); obs.refresh(this); } } }
4.主題子類定義被監控數據(Subject)。代碼如下:
public class Subject extends AbstractSubject{ //被監控的數據 private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } }
5.觀察者對象(Observer)“拉”數據得到數據響應。代碼如下:
public class Observer implements IObserver { @Override public void refresh(ISubject obj) { // TODO Auto-generated method stub Subject subject = (Subject)obj; System.out.println("數據正在更新為:"+subject.getData()); } }
最后來寫一個測試類來測試一下:
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub IObserver obs = new Observer(); Subject subject = new Subject(); subject.register(obs); subject.setData("one"); subject.notifyObservers(); } }
輸出結果是一樣的!