該模式定義了一個一對多的關(guān)系点楼,一個被觀察對象與一群觀察對象存在依賴關(guān)系,一旦這個被觀察對象有什么風(fēng)吹草動卸夕,其他的觀察者就都能收到通知。其實本質(zhì)是被觀察對象通知所有觀察者對象截驮。
軟件系統(tǒng)很多時候需要這樣的情況笑陈,一旦發(fā)生故障,就通知對應(yīng)的系統(tǒng)或模塊侧纯,使之能夠及時處理新锈。
觀察者類圖結(jié)構(gòu)
- 抽象主題 Subject:提供添加和減少觀察者方法和通知觀察者方法;
- 具體主題 ConcreteSubject:對抽象主題的實現(xiàn)眶熬,包含一個觀察者的集合[這里是接口哦妹笆,我們是針對接口編程的],用以操作與觀察者之間的互動娜氏;
- 抽象觀察者 Observer:提供被主題調(diào)用的方法拳缠,一旦主題變動,就調(diào)用這個方法贸弥;
- 具體觀察者 ConcreteObserver:對抽象觀察者的抽象調(diào)用方法進(jìn)行實現(xiàn)窟坐。
有了上面的類圖,很快就把代碼切出來:
public interface Subject {
public void attach(Observer observer);
public void detach(Observer observer);
public void notifyObservers();
}
以上就是抽象主題的基本代碼绵疲,大抵上可以完成任務(wù)了
public interface Observer {
public void update();
}
抽象觀察者哲鸳,這里簡化,只有一個公開方法被主題調(diào)用
接下來把具體的主題構(gòu)造出來盔憨,如下所示
import java.util.ArrayList;
import java.util.List;
public class ConcreteSubject implements Subject{
//裝載所有觀察者的容器
private List<Observer> observers=null;
//構(gòu)造方法里面初始化容器
public ConcreteSubject() {
observers=new ArrayList<Observer>();
}
@Override
public void attach(Observer observer) {
if(!observers.contains(observer)){
observers.add(observer);
}
}
@Override
public void detach(Observer observer) {
if(observers.contains(observer)){
observers.remove(observer);
}
}
@Override
public void notifyObservers() {
for(Observer observer:observers){
observer.update();
}
}
}
其主要任務(wù)就是綁定和解綁觀察者徙菠,以及有事通知觀察者,當(dāng)然可以對觀察者進(jìn)行分類郁岩,根據(jù)分類再進(jìn)行通知婿奔。
最后是具體的觀察者,主要工作代碼如下
public class ConcreteObserver implements Observer{
private String name;
public ConcreteObserver(String name) {
this.name=name;
}
@Override
public void update() {
System.out.println(this.name+"被調(diào)用了问慎,在時間:"+new Date());
}
}
運(yùn)行下來看看
public class Client {
public static void main(String[] args) {
Observer o1=new ConcreteObserver("張三");
Observer o2=new ConcreteObserver("李四");
Subject subject=new ConcreteSubject();
subject.attach(o1);
subject.attach(o2);
subject.notifyObservers();
subject.detach(o2);
subject.notifyObservers();
}
}
非常完美的實現(xiàn)了主題通知觀察者萍摊。需要注意的是,在具體主題里面的集合容器最好不要使得外界可以修改如叼,以及線程安全方面需要考慮冰木。
另外一種方式把主題作為抽象類,然后關(guān)聯(lián)到抽象觀察者笼恰,而具體主題負(fù)責(zé)把狀態(tài)改變后片酝,調(diào)用抽象的通知方法;
來段代碼實際情況看看挖腰;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractSubject {
// 裝載所有觀察者的容器
private List<Observer> observers = null;
// 構(gòu)造方法里面初始化容器
public AbstractSubject() {
observers = new ArrayList<Observer>();
}
public void attach(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
public void detach(Observer observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
//具體主題務(wù)必實現(xiàn)這個方法
protected String state;
public abstract void change(String newState);
}
這個抽象主題比較能干,把子類要做到事多包攬了练湿,子類的工作就輕松多了猴仑,來看下
public class ConcreteSubject2 extends AbstractSubject{
@Override
public void change(String newState) {
this.state=newState;
System.out.println("當(dāng)前主題狀態(tài)修改為"+this.state);
notifyObservers();
}
}
具體主題就實現(xiàn)了一個方法,頓時輕松,觀察者和上面一樣辽俗,來看下客戶端怎么使用
public class Client {
public static void main(String[] args) {
Observer o1=new ConcreteObserver("張三");
Observer o2=new ConcreteObserver("李四");
// Subject subject=new ConcreteSubject();
// subject.attach(o1);
// subject.attach(o2);
// subject.notifyObservers();
// subject.detach(o2);
// subject.notifyObservers();
AbstractSubject subject=new ConcreteSubject2();
subject.attach(o1);
subject.attach(o2);
subject.change("A");
subject.detach(o2);
subject.change("B");
}
}
JDK 自帶了觀察者模式的一些基本類疾渣,可以使用,但最好還是自己造一個更方便崖飘,里面的源碼可以借鑒看看榴捡,考慮的很詳細(xì)。