說明:本文參照《大話設計模式》中的案例做簡要解析
觀察者模式:
又叫釋出-訂閱模式,定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在發生變化時,會通知所有觀察者對象,使他們能夠更新自己。
我自己的了解,可以拿咱們都比較熟悉的上課來做比喻,在一個教室裡,老師就是通知者,所有正在上課的學生就是觀察者,老師說下課,所有的學生下課回家。老師說的“下課”,就是這裡的“主題”,也可以叫話題(Topic),學生接受到這個“主題”,采取相應的動作-(收拾東西回家)。
類圖及簡要說明:
Subject類,可了解為主題或者抽象通知者,一般用抽象類或接口實作。它把所有的觀察者對象的引用儲存在一個集合裡,每個主題都可以有任何數量的觀察者。
package com.uu.designPattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
***********************************************
* 主題或抽象通知者
* 一般用一個抽象類或一個接口實作,把所有對觀察者的引用儲存在一個集合裡,每一個主題都可以有任何數量的觀察者。
* 抽象主題提供一個接口,可以增加和删除觀察者。
* @author UU
* @date 2018年7月5日 下午3:00:23
* @version 1.0
***********************************************
*/
public abstract class Subject {
List<Observer> observers = new ArrayList<>();
/**添加觀察者*/
public abstract void attach(Observer observer);
/**移除觀察者*/
public abstract void detach(Observer observer);
/**
* 通知觀察者
*/
public void notifyAllObserver() {
observers.forEach(Observer::update);
}
}
Observer,抽象觀察者,為所有的具體觀察者定義一個接口,在得到主題的通知時,更新自己。這個接口稱為更新接口,更新接口一般都有一個update方法。
package com.uu.designPattern.observer;
/**
***********************************************
* 觀察者
* @author UU
* @date 2018年7月5日 下午3:02:34
* @version 1.0
***********************************************
*/
public abstract class Observer {
public abstract void update();
}
ConcreteSubject,具體的主題或具體的通知者,将有關狀态存入具體觀察者對象;在具體主題的内部狀态發生改變時,給所有已經注冊的觀察者發出通知。其實這裡的意思主要是觸發通知者發出通知,然後觀察者根據通知資訊作出相應的動作。
package com.uu.designPattern.observer;
/**
***********************************************
* 具體的主題或通知者,将有關狀态存入具體主題對象,在具體的主題對象的内部狀态發生改變時,通知所有已經注冊的觀察者
* @author UU
* @date 2018年7月5日 下午3:42:40
* @version 1.0
***********************************************
*/
public class ConcreteSubject extends Subject{
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public void attach(Observer observer) {
this.observers.add(observer);
}
@Override
public void detach(Observer observer) {
this.observers.remove(observer);
}
}
ConcreteObserver,具體的觀察者,實作抽象觀察者所要實作的更新方法,以便使自身的狀态與主題的狀态保持一緻。具體觀察者包含一個具體主題對象的引用。
package com.uu.designPattern.observer;
/**
***********************************************
* 具體的觀察者
*
* @author UU
* @date 2018年7月5日 下午3:46:47
* @version 1.0
***********************************************
*/
public class ConcreteObserver extends Observer {
private String name;
private String state;
private ConcreteSubject subject;
public ConcreteObserver(String name, ConcreteSubject subject) {
super();
this.name = name;
this.subject = subject;
}
@Override
public void update() {
state = subject.getState();
System.out.println("觀察者" + this.name + "的新狀态是:" + state);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public ConcreteSubject getSubject() {
return subject;
}
public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}
測試類:
package com.uu.designPattern.observer;
public class ObserverTest {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.attach(new ConcreteObserver("AA", subject));
subject.attach(new ConcreteObserver("BB", subject));
subject.setState("ABC");
subject.notifyAllObserver();
subject.setState("CCC");
subject.notifyAllObserver();
}
}
運作結果:
觀察者AA的新狀态是:ABC
觀察者BB的新狀态是:ABC
觀察者AA的新狀态是:CCC
觀察者BB的新狀态是:CCC
觀察者模式的特點:
主要是為了解決各類直接的耦合度,一個出題可以有任意數量的觀察者,一旦主題發生改變,所有注冊的觀察者都可以得到通知。主題發出通知時,并不需要知道他的觀察者都是哪些,也就是說,具體的觀察者是誰,他根本不需要知道,而任何一個觀察者不知道也不需要知道其他觀察者的存在。
再拿老師和學生來講,老師不需要知道每個學生都是誰(也許是剛來的新老師),老師隻需要發出下課的指令就可以了,然後這個指令會被所有正在上課的學生接受到。對于每個學生個體而言,也不需要知道是否有其他學生是否存在,隻要接受到老師的指令,照做就OK了。
觀察者模式的應用場景:
當一個對象的改變需要同時改變其他對象時,并且它不知道具體有多少對象需要改變。
總的來講,觀察者模式所做的工作就是解除耦合,讓耦合的雙方都依賴于抽象,而不是依賴于具體。進而使得各自的變化都不會影響到另一邊的變化。
在Dubbo的注冊中心Zookeeper中的服務注冊和訂閱應用的就是這種模式。
以上全是個人見解,若有錯誤,還望指正。