1. 問題場景
當一個對象的狀态放生改變的時候,如何讓依賴于它的所有對象得到通知,并進行相應的處理?
2. UML圖
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2PnVGcq5idmlmYxoGdldDdvwlMzgzN2YTMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.jpeg)
Subject:目标對象,通常具有以下功能
- 一個目标對象可以被多個觀察者觀察
- 目标提供觀察者注冊和退訂的維護
- 當目标狀态發生改變時,目标負責通知所有注冊的、有效的觀察者
Observer:定義觀察者接口,提供目标通知時對應的更新方法,這個更新方法進行相應的業務邏輯處理,可以在這個方法回調目标對象,以擷取目标對象的資料
ConcreteSubject:具體的目标對象,用來維護目标的狀态,當目标狀态發生改變時,通知所有注冊有效的觀察者,讓觀察者執行相應的處理
ConcreteObserver:觀察者的具體對象,用來接收目标的通知,并進行相應的後續處理
3. 具體代碼實作代碼:
// Subject:public class Subject {
//注意:Arraylist裡面可以添加null元素
private List<Observer> readers = new ArrayList<>(); public void attach(Observer reader){ if(reader != null){
readers.add(reader);
}
} public void detach(Observer reader){ if(reader != null){
readers.remove(reader);
}
} public void notifyAllReaders(){ if(readers.size() != 0){ //通過流的方式來通路
//因為是從Newapaper方法裡調用,所有this表示Newspaper執行個體
readers.forEach(reader -> reader.update(this));
}
}
}//Newspaper:public class Newspaper extends Subject{
private String content; public String getContent(){ return content;
} //維護目标的狀态
public void setContent(String content){ //内容更新之後通知所有觀察者
this.content = content;
notifyAllReaders();
}
}// Observer:public interface Observer {
public void update(Subject subject);
}// Reader:public class Reader implements Observer {
private String name; public void setName(String name) { this.name = name;
} public String getName() { return name;
} @Override
public void update(Subject subject) {
System.out.println(name + "收到了報紙\n 報紙的内容為: "
+ ((Newspaper)subject).getContent() );
}
}//Client端public class Client {
public static void main(String[] args) { //建立一個報紙,作為被觀察者
NewsPaper subject = new NewsPaper(); //建立閱讀者,也就是觀察者
Reader reader1 = new Reader();
reader1.setName("張三");
Reader reader2 = new Reader();
reader2.setName("李四");
Reader reader3 = new Reader();
reader3.setName("王五"); //注冊閱讀者
subject.attach(reader1);
subject.attach(reader2);
subject.attach(reader3); //要出報紙啦
subject.setContent("本期内容是觀察者模式");
}
}
複制
4. 研磨設計模式
觀察者模式的定義:
定義對象間的一種一對多的依賴關系,當一個對象的狀态發生改變時,所有依賴于它的對象都得到通知并被自動更新。
觀察者模式把多個訂閱者稱為觀察者Observer,多個觀察者觀察的對象的被稱為目标Subject。
一個目标可以有任意多個觀察者對象,一旦目标的狀态發生改變時,所有注冊的觀察者就會得到通知,然後各個觀察者會對通知作出相應的處理,執行相應的業務功能處理,并使自己的狀态和目标對象的狀态保持一緻。
觀察者模式的本質:觸發關聯
Swing中的觀察者模式:Swing元件是被觀察的目标,而每個實作監聽的類就是觀察者,監聽器的接口就是觀察者的接口,在調用addXXXListener方法的時候就相當于注冊觀察者。當元件被單擊時,狀态發生改變的時候,就會産生相應的通知,會調用注冊的觀察者的方法,就是我們所實作的監聽器的方法。
擴充:差別對待觀察者
/**
* 定義水質監測的目标對象
*/public abstract class WaterQualitySubject {
/**
* 用來儲存注冊的觀察者對象
*/
protected List<WatcherObserver> observers = new ArrayList<WatcherObserver>(); /**
* 注冊觀察者對象
* @param observer 觀察者對象
*/
public void attach(WatcherObserver observer) {
observers.add(observer);
} /**
* 删除觀察者對象
* @param observer 觀察者對象
*/
public void detach(WatcherObserver observer) {
observers.remove(observer);
} /**
* 通知相應的觀察者對象
*/
public abstract void notifyWatchers(); /**
* 擷取水質污染的級别
* @return 水質污染的級别
*/
public abstract int getPolluteLevel();
}/**
* 具體的水質監測對象
*/public class WaterQuality extends WaterQualitySubject{
/**
* 污染的級别,0表示正常,1表示輕度污染,2表示中度污染,3表示高度污染
*/
private int polluteLevel = 0; /**
* 擷取水質污染的級别
* @return 水質污染的級别
*/
public int getPolluteLevel() { return polluteLevel;
} /**
* 當監測水質情況後,設定水質污染的級别
* @param polluteLevel 水質污染的級别
*/
public void setPolluteLevel(int polluteLevel) { this.polluteLevel = polluteLevel; //通知相應的觀察者
this.notifyWatchers();
} /**
* 通知相應的觀察者對象
*/
public void notifyWatchers() { //循環所有注冊的觀察者
for(WatcherObserver watcher : observers){ //開始根據污染級别判斷是否需要通知,由這裡總控
if(this.polluteLevel >= 0){ //通知監測員做記錄
if("監測人員".equals(watcher.getJob())){
watcher.update(this);
}
} if(this.polluteLevel >= 1){ //通知預警人員
if("預警人員".equals(watcher.getJob())){
watcher.update(this);
}
} if(this.polluteLevel >= 2){ //通知監測部門上司
if("監測部門上司".equals(watcher.getJob())){
watcher.update(this);
}
}
}
}
}/**
* 水質觀察者接口定義
*/public interface WatcherObserver {
/**
* 被通知的方法
* @param subject 傳入被觀察的目标對象
*/
public void update(WaterQualitySubject subject); /**
* 設定觀察人員的職務
* @param job 觀察人員的職務
*/
public void setJob(String job); /**
* 擷取觀察人員的職務
* @return 觀察人員的職務
*/
public String getJob();
}/**
* 具體的觀察者實作
*/public class Watcher implements WatcherObserver{
/**
* 職務
*/
private String job; public void update(WaterQualitySubject subject) { //這裡采用的是拉的方式
System.out.println(job+"擷取到通知,目前污染級别為:"+subject.getPolluteLevel());
} public String getJob() { return this.job;
} public void setJob(String job) { this.job = job;
}
}public class Client {
public static void main(String[] args) { //建立水質主題對象
WaterQuality subject = new WaterQuality(); //建立幾個觀察者
WatcherObserver watcher1 = new Watcher();
watcher1.setJob("監測人員");
WatcherObserver watcher2 = new Watcher();
watcher2.setJob("預警人員");
WatcherObserver watcher3 = new Watcher();
watcher3.setJob("監測部門上司"); //注冊觀察者
subject.attach(watcher1);
subject.attach(watcher2);
subject.attach(watcher3); //填寫水質報告
System.out.println("當水質為正常的時候------------------〉");
subject.setPolluteLevel(0);
System.out.println("當水質為輕度污染的時候---------------〉");
subject.setPolluteLevel(1);
System.out.println("當水質為中度污染的時候---------------〉");
subject.setPolluteLevel(2);
}
}
複制