天天看點

設計模式之觀察者模式(Java實作)

    觀察者模式是設計模式中常見的一種模式,他的思想猶如他的名字一樣,就是想建構一個觀察者觀察他所關注的主題,當主題發生變化了,就會通知觀察者。觀察者模式也叫釋出訂閱模式,這種設計模式用在了很多地方,比如zookeeper的節點觀察機制。

    這裡我們建構一個如下模型,Subject<-AbstractSubject<-TopSubject  與 Observer<-Watcher,他們的關系如下圖所示:

設計模式之觀察者模式(Java實作)

通過java實作:

Observer.java

package com.xxx.design.watcher;

public interface Observer {
	void update();
}
           

Watcher.java

package com.xxx.design.watcher;
/**
 * 觀察者
 *
 */
public class Watcher implements Observer {
	
	private String name;
	public Watcher(String name) {
		this.name = name;
	}

	@Override
	public void update() {
		System.out.println("watcher "+name+" update state.");
	}

}
           

Subject.java

package com.xxx.design.watcher;

public interface Subject {
	void add(Observer observer);
	void delete(Observer observer);
	void notifyObserver();
	void action();
}
           

AbstractSubject.java

package com.xxx.design.watcher;
import java.util.Enumeration;
import java.util.Vector;
public abstract class AbstractSubject implements Subject{
	private Vector<Observer> obs = new Vector<Observer>();
	
	@Override
	public void add(Observer observer) {
		obs.add(observer);
	}
	
	@Override
	public void delete(Observer observer) {
		obs.remove(observer);
	}
	
	@Override
	public void notifyObserver() {
		Enumeration<Observer> eles = obs.elements();
		while(eles.hasMoreElements()){
			eles.nextElement().update();
		}
	}
}
           

TopSubject.java

package com.xxx.design.watcher;

public class TopSubject extends AbstractSubject {

	@Override
	public void action() {
		System.out.println("i am a subject,update now.");
		notifyObserver();
	}
	
	public static void main(String[] args) {
		Subject subject = new TopSubject();
		subject.add(new Watcher("aa"));
		subject.add(new Watcher("bb"));
		subject.add(new Watcher("cc"));
		subject.action();
	}

}
           

    運作程式,列印結果如下:

i am a subject,update now.
watcher aa update state.
watcher bb update state.
watcher cc update state.
           

    觀察者需要注意的是:避免循環引用,如果是順序執行,考慮采用異步實作,避免因為一個處理異常導緻整個系統卡殼。另外,現在java.util包中api已經提供了觀察者模式的實作。我們可以利用Observable類和Observer接口來實作一個觀察者模式:

Subscribe.java

package com.xxx.design.watcher.jdk;

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

public class Subscribe implements Observer {
	
	private String name;
	public Subscribe(String name){
		this.name = name;
	}
	
	public void add(Observable o){
		o.addObserver(this);
	}

	@Override
	public void update(Observable o, Object arg) {
		System.out.println(name+" 收到通知:"+((Publish)o).getData());
	}

}
           

Publish.java

package com.xxx.design.watcher.jdk;
import java.util.Observable;
public class Publish extends Observable {
	private String data = "";
	public String getData() {
		return data;
	}
	
	public void setData(String data) {
		if(!this.data.equals(data)){
			this.data = data;
			setChanged();
		}
		notifyObservers();
	}
	
	public static void main(String[] args) {
		Publish publish = new Publish();
		Subscribe subscribe = new Subscribe("aaa");
		subscribe.add(publish);
		Subscribe subscribe2 = new Subscribe("bbb");
		subscribe2.add(publish);
		publish.setData("start");
		publish.setData("end");
	}
}
           

運作程式,列印資訊如下:

bbb 收到通知:start
aaa 收到通知:start
bbb 收到通知:end
aaa 收到通知:end