1. 程式人生 > >Java常用設計模式————觀察者模式

Java常用設計模式————觀察者模式

引言

作為設計模式中常用的行為型模式,其主要解決的是一個複合物件(或組合物件)的基礎依賴物件的通知問題。

簡單的說,當一個複合物件依賴多個其他物件時,我們稱這種關係為一對多的關係。當這個複合物件狀態發生了改變,其他組成它的物件都可以收到來自複合物件的通知。

依賴物件中存在一個指向複合物件的引用。

實現步驟

實現參考《菜鳥教程——設計模式:觀察者模式

功能實現:實現一個進位制轉換器,它主要由一個包含二進位制、八進位制以及十六進位制的基礎轉換器 List 和一個可變狀態組成。通過觀察者模式實現複合轉換器到基礎進位制轉換器的狀態變更通知。

步驟一:定義基礎元件及其抽象類

首先,定義一個基礎轉換器的抽象類BaseConverter,程式碼如下:

public abstract class BaseConverter {
        /** 複合物件Converter的引用 */
	protected Converter converter;

	public abstract void update();
}

其次,定義具體實現的基礎轉換類:BinaryConverter、OctalConverter、HexConverter,程式碼如下:

public class BinaryConverter extends BaseConverter {

	public BinaryConverter(Converter converter) {
		this.converter = converter;
		this.converter.attach(this);
	}

	@Override
	public void update() {
		System.out.println("Binary String : " + Integer.toBinaryString(converter.getState()));
	}
}
public class OctalConverter extends BaseConverter {

	public OctalConverter(Converter converter) {
		this.converter = converter;
		this.converter.attach(this);
	}

	@Override
	public void update() {
		System.out.println("Octal String : " + Integer.toOctalString(converter.getState()));
	}
}
public class HexConverter extends BaseConverter {

	public HexConverter(Converter converter) {
		this.converter = converter;
		this.converter.attach(this);
	}

	@Override
	public void update() {
		System.out.println("Hex String : " + Integer.toHexString(converter.getState()).toUpperCase());
	}
}

步驟二:定義複合物件

複合物件Converter是一個由待轉化的十進位制數,和一個包含各種轉化器的List組成的物件,我們的目的是:當state變數發生了變化後,baseConverters 中的每個物件都可以得知複合物件中state的變化。

public class Converter {
	/** Converter 依賴於一個BaseConverter物件組成的List */
	private List<BaseConverter> baseConverters = new ArrayList<>();
	/** 一個可變的狀態,觀察者真正關心的可變物件 */
	private int state;

	public void attach(BaseConverter observer) {
		baseConverters.add(observer);
	}

	/**
	 * 通知所有的觀察者更新
	 */
	public void notifyAllConverters() {
		for (BaseConverter cvter : baseConverters)
			cvter.update();
	}

	// --------------GET/SET----------------

	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
		notifyAllConverters();
	}
}

步驟三:測試

public class ObserverPatternProgram {

	public static void main(String[] args) {
		Converter cvter = new Converter();

		new HexConverter(cvter);
		new OctalConverter(cvter);
		new BinaryConverter(cvter);

		System.out.println("第一個需要轉化的十進位制數是 : 15");
		cvter.setState(15);
		System.out.println("\n第二個需要轉化的十進位制數是 : 10");
		cvter.setState(10);
	}
}

輸出結果是:

總結

        我們的需求可能不侷限於上述的程式碼功能,但觀察者模式的實現基本一樣,雖然不一定是包含一個List,而是單獨的各個模組組成一個複合物件。但是,最關鍵的一點就是在依賴物件中一定要包含一個複合物件的引用。當複合物件的某些狀態發生變化,那麼複合物件就會告知依賴物件它們所關心的某些狀態發生了變化。

      這也正是“觀察者”的真正含義,即依賴物件始終觀察著包含在自己物件中的複合物件的引用。而複合物件需要做的,僅僅是在變更某些狀態時,呼叫通知操作。

      在本例中,可能會有讀者覺得哪裡有些彆扭。

      這是因為進位制轉換器的功能更像是一個人機互動的計算器功能,輸入的數值不應該以物件的狀態而存在。上述程式碼,我們通過一個可變的int 變數來儲存這個將要被轉化的十進位制數,這可能就是讀者覺得彆扭的地方。把使用者輸入的數字封裝成一個狀態可能不是很恰當。但是我們大可跳出這個應用案例,去考慮更加一般的情況,如執行緒,那麼這個複合物件的可變狀態就可能是完全自主變化的任意型別的變數。所以從這個角度來講我們也就能夠更好的理解觀察者模式,實際上觀察者觀察的就是封裝在複合物件中的一個或多個狀態,因此我們才會將使用者輸入的十進位制數以狀態的形式封裝在進位制轉換器中。

      由此,我們也可以總結實現觀察者模式的幾點要素:

1、複合物件必須具備一個或多個可變狀態,否則觀察將無從談起;

2、依賴物件必須包含一個指向複合物件的引用,以便能夠在接到通知時取得複合物件的可變狀態;

3、複合物件和依賴物件必須具備依賴關係,這樣複合物件才能夠在狀態變更時通知到它的依賴物件;

4、只有在複合物件的狀態改變時才去通知依賴物件。

(擴充套件)5、依賴物件不一定需要取得複合物件的全部狀態,複合物件的狀態變更也不一定需要告知全部依賴物件。

鳴謝

觀察者模式

綜上,就是博主對觀察者模式的理解,如有疑問,歡迎文末留言。