1. 程式人生 > >設計模式之觀察者模式(Obsever)

設計模式之觀察者模式(Obsever)

(1)觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態上發生變化時,會通知所有觀察者物件,讓他們能夠自動更新自己。

(2)觀察者模式的組成

抽象主題角色:把所有對觀察者物件的引用儲存在一個集合中,每個抽象主題角色都可以有任意數量的觀察者。抽象主題提供一個藉口,可以增加和刪除觀察者角色。一般用一個抽象類或介面來實現。

抽象觀察者角色:為所有具體的觀察者定義一個介面,在得到主題的通知時更新自己

具體主題角色:在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。具體主題角色通常用一個子類實現。

具體觀察者角色:該角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調。如果需要,具體觀察者角色可以儲存一個指向具體主題角色的引用。通常用一個子類實現。

(3)下面是一個觀察者模式的例子

 抽象主題角色:

package com.sailang.obsever;

public interface Watched
{
	public void addWatcher(Watcher watcher);
	
	public void removeWatcher(Watcher watcher);
	
	public void notifyWatchers(String str);
}

抽象觀察者角色:

package com.sailang.obsever;

public interface Watcher
{
	public void upDate(String str);
}

具體主題角色:

package com.sailang.obsever;

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

public class ConcreteWatched implements Watched
{
	private List<Watcher> list = new ArrayList<Watcher>();
	
	@Override
	public void addWatcher(Watcher watcher)
	{
		list.add(watcher);
	}

	@Override
	public void removeWatcher(Watcher watcher)
	{
		list.remove(watcher);
	}

	@Override
	public void notifyWatchers(String str)
	{
		for(Watcher watcher : list)
		{
			watcher.upDate(str);
		}
	}
}

具體觀察者角色:

package com.sailang.obsever;

public class ConcreteWatcher implements Watcher
{
	@Override
	public void upDate(String str)
	{
		System.out.println(str);
	}
}

客戶端:

package com.sailang.obsever;

public class Test
{
	public static void main(String[] args)
	{
		Watched watched = new ConcreteWatched();
		
		Watcher watcher1 = new ConcreteWatcher();
		Watcher watcher2 = new ConcreteWatcher();
		Watcher watcher3 = new ConcreteWatcher();
		
		//將所有的觀察物件在主題物件中進行註冊
		watched.addWatcher(watcher1);
		watched.addWatcher(watcher2);
		watched.addWatcher(watcher3);
		
		//主題物件狀態改變
		watched.notifyWatchers("Hello");
	}
}


 (4)在AWT中事件模型所採用的就是觀察者模式,如下面的例子:

package com.sailang.obsever2;

import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test
{
	public static void main(String[] args)
	{
		Frame frame = new Frame();
		Button button = new Button("點我");
		button.addActionListener(new ButtonListener());
		
		frame.add(button);
		frame.pack();
		frame.setVisible(true);
	}
}
class ButtonListener implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String label = e.getActionCommand();
		
		System.out.println(label);
	}
}

Button就是具體主題角色,ActionListener是抽象觀察者角色,ButtonListener是具體觀察者角色。

actionPerformed()就是抽象觀察角色為所有具體觀察者角色定義的一個介面,用於得到主題角色的通知來更新自己。

button.addActionListener()就是把一個觀察物件加到自己的List中。

而狀態的更新就是“點選按鈕”,這個不用開發者來操心,內部機制會幫我們實現,從外表來看就好像是自動呼叫似的。

(5)編寫一個程式,宣告一個類,該類繼承自Observable(因此該類是個主題角色),有一個int型別的變數,初始值為10,編寫一個for迴圈,將該數字每次遞減1,一直到0為止,每次變化時,都將該數字傳遞給它的觀察者,觀察者會打印出該數字;第二個觀察者在該數字為5之後開始列印該數字。

主題物件(即被觀察物件)

package com.sailang.obsever2;

import java.util.Observable;

public class BeingWatched extends Observable
{
	public void counter()
	{
		for(int i = 10; i >= 0; i--)
		{
			setChanged();
			notifyObservers(i);
		}
	}
}
觀察物件1
package com.sailang.obsever2;

import java.util.Observable;
import java.util.Observer;

public class Watcher implements Observer
{
	@Override
	public void update(Observable o, Object arg)
	{
		System.out.println(arg);
	}
}

觀察物件2

package com.sailang.obsever2;

import java.util.Observable;
import java.util.Observer;

public class Watcher2 implements Observer
{
	@Override
	public void update(Observable o, Object arg)
	{
		if((Integer)arg > 5)
			return;
		System.out.println(arg);
	}
}

客戶端:

package com.sailang.obsever2;

public class Test2
{
	public static void main(String[] args)
	{
		BeingWatched beingWatched = new BeingWatched();
		Watcher watcher = new Watcher();
		Watcher2 watcher2 = new Watcher2();
		
		beingWatched.addObserver(watcher);
		beingWatched.addObserver(watcher2);
		//狀態改變
		beingWatched.counter();
	}
}