Java 設計模式之《觀察者模式》

maweiliang發表於2018-10-10

       很久之前,自己也曾看過一些設計模式的內容,最近在做一些程式程式碼設計的時,發現忘得差不多了,很多模式也只是有大致影響,決定重新將一些常用的模式複習一下。今天一個模式觀察者模式。

觀察者模式

       觀察者模式屬於行為模式中的一種;觀察者模式定物件一個一對多的依賴關係,讓多個觀察者物件同時監聽同一個主題物件,主題物件在狀態發生改變時,通知所有觀察者物件使他們能夠更新自己。

類圖
上面是觀察者模式設計類圖

  • subject:它是抽象主題的介面,物件通過此介面將自己註冊為觀察者,或將自己從觀察中者刪除

  • ConcreteSubject:一個實現主題介面的具體主題,除了實現註冊和刪除的方法外,它還有一個change方法,用來在狀態改變時通知所有觀察者

  • Observer:觀察者介面,所有具體的觀察者都實現此介面

  • ConcreteObserver:具體的觀察者

package com.mtx.demo.observer;

import java.util.ArrayList;
import java.util.List;

public abstract class Subject {

	// 儲存註冊的觀察者物件
	private List<Observer> list = new ArrayList<Observer>();

	// 註冊觀察者物件
	public void attach(Observer observer) {
		list.add(observer);
		System.out.println("新增新的觀察者");
	}

	// 刪除觀察者物件
	public void detach(Observer observer) {
		list.remove(observer);
		System.out.println("刪除一個觀察者");
	}

	// 通知所有註冊的觀察者物件
	public void nodifyObservers(String newState) {
		for (Observer observer : list) {
			observer.update(newState);
		}
	}
}
複製程式碼

一個具體主題

package com.mtx.demo.observer;

public class ConcreteSubject extends Subject {

	private String state;

	public String getState() {
		return state;
	}

	// 狀態發生改變,通知各個觀察者
	public void change(String newState) {
		state = newState;
		this.nodifyObservers(state);
	}
}
複製程式碼

抽象的觀察者

package com.mtx.demo.observer;

public interface Observer {
	// 更新介面
	public void update(String state);
}
複製程式碼

一個具體觀察者

package com.mtx.demo.observer;

public class ConcreteObserver implements Observer {

	private String observerState;

	@Override
	public void update(String state) {
		observerState = state;
		System.out.println("觀察者狀態跟新了:" + observerState);
	}
}
複製程式碼

客戶端中,我們建立一個具體主題物件,在建立一個觀察者物件,之後將觀察註冊到主題物件像上,這樣當主題物件的狀態改變時,所有的觀察者物件都會收到通知,改變自己的狀態。

package com.mtx.demo.observer;

public class Client {

	public static void main(String[] args) {
		// 建立主題物件
		ConcreteSubject subject = new ConcreteSubject();
		// 建立觀察者物件
		Observer observer = new ConcreteObserver();
		// 將觀察者物件登記到主題物件上
		subject.attach(observer);
		// 改變主題物件的狀態
		subject.change("有新的技術部落格了");
	}

}
複製程式碼

執行程式碼結果如下

結果檔案

問題

  • 觀察者模式中一對多是如何體現的

主題是一個具有狀態的物件,而多個觀察者可以使用這個主題的狀態,多個觀察者依賴主題物件來告訴他們這些狀態何時改變,這就產生了一個主題對應多觀察者的關係

  • 觀察者模式是鬆如何做到耦合的

主題只知道觀察者實現了某一個介面(Observer介面),主題不用知道觀察者具體是誰,做了哪些操作等,任何時候我們都可以新增新的觀察者,那是因為主題唯一依賴的是一個觀察者的Observer介面的物件列表,因此我們可以隨時新增觀察者,有新的主題出現時主題程式碼不用修改。

推模型和拉模型。

  • 推模型:主題物件向觀察者推送主題的詳細資訊,不管觀察者是否需要,推送的資訊通常是主題物件的全部或部分資料,剛才上面的例子就是一個推模型。

推模型會是觀察者難以複用,因為每個觀察者的updata方法的引數可能不同,資料量非常大的時候推模型不適合

  • 拉模型:主題物件在通知觀察者的時候,只傳遞少量資訊。如果觀察者需要更具體的資訊,由觀察者主動到主題物件中獲取,相當於是觀察者從主題物件中拉資料。一般這種模型的實現中,會把主題物件自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取資料的時候,就可以通過這個引用來獲取了。

另外Java語言提供的對觀察者模式的支援,在java.util包中,提供了一個Observable類以及一個Observer介面

  • 優點:

1.在觀察者和被觀察者之間建立一個抽象的耦合;

2.支援廣播通訊

  • 缺點:

1.如果一個被觀察者物件有很多觀察者,將所有觀察者通知到會花費很多時間;

2.如果在被觀察者之間有迴圈依賴,被觀察者會觸發他們之間的迴圈呼叫,導致系統崩潰;

3.觀察者沒有相應的方式使其知道所觀察的物件時怎麼發生變化的。

參考:Head First 設計模式

相關文章