一、簡介
觀察者模式是一種使用率很高的模式。這個模式的一個重要作用就是解耦,将被觀察者和觀察者解耦。在很多地方,都會将觀察者模式稱為釋出-訂閱模式,或者訂閱者模式。實際上,兩者是不完全相同的,有聯系也有差別。
二、觀察者模式定義
觀察者模式,定義了一種一對多的依賴關系,使得當一個對象發生狀态變化時,則觀察它的對象也都得到通知并作出反應。
三、UML類圖
- 抽象主題(Subject):它把所有觀察者對象的引用儲存到一個集合中,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以注冊和移除觀察者。
- 具體主題(ConcreteSubject):将有關狀态存入具體觀察者對象;在具體主題内部狀态改變時,給所有登記過的觀察者發出通知。
- 抽象觀察者(Observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
- 具體觀察者(ConcreteObserver):實作抽象觀察者提供的更新接口,以便本身的狀态能夠及時更新。
四、觀察者模式的實作例子
1、建立一個抽象觀察者
public interface Observer {//抽象觀察者
public void update(String message);//更新方法
}
2、建立具體觀察者(以開學為例)
public class Student implements Observer {
private String name;
public Student (String name) {
this.name = name;
}
@Override
public void termBegins(String message) {
System.out.println(message + "," + name+"背上書包去學校");
}
}
public class Teacher implements Observer {
private String name;
public Teacher (String name) {
this.name = name;
}
@Override
public void termBegins(String message) {
System.out.println(message + "," + name+"準備布置新學期學習任務");
}
}
3、建立抽象主題
public interface Observable {
void add(Observer observer);
void remove(Observer observer);
void notify(String message);
}
4、建立具體主題
public class School implements Observable{
private List<Observer> personList = new ArrayList<Observer>();
@Override
public void add(Observer observer) {
personList.add(observer);
}
@Override
public void remove(Observer observer) {
personList.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : personList) {
observer.termBegins(message);
}
}
}
5、用戶端測試
public void test(){
Observable school = new School();
Observer stu1=new Student("小明");
Observer teacher1=new Teacher("王老師");
school.add(stu1);
school.add(teacher1);
school.notify("開學了!");
}
五、釋出-訂閱模式
聯系
釋出-訂閱模式是觀察者模式的一種變體。釋出-訂閱隻是把一部分功能抽象成一個獨立的“中間件”進行轉發控制。
差別
1、觀察者模式中主體和觀察者是互相感覺的,釋出-訂閱模式是借助第三方來實作排程的,釋出者和訂閱者之間互不感覺。
觀察者模式比較好了解,釋出訂閱模式舉個栗子,就像報社, 郵局和個人的關系,報紙的訂閱和分發是由郵局來完成的。報社隻負責将報紙發送給郵局。
2、觀察者模式是【一對多】的關系。一觸發通知,所有觀察者都收到消息。
釋出-訂閱模式是【多對一】或者【多對多】的關系。
釋出-訂閱模式适合更複雜的場景,比如隻想通知部分訂閱者,比如多個釋出者釋出消息時,通知時機的選擇(都釋出完再通知還是每釋出一個通知一次)。而這些控制的邏輯就是在“中間件”完成的。
六、釋出-訂閱模式例子
var publisher = {
publish(pubsub) {
pubsub.publish()
}
}
var pubsub = {
subscribes: [],
publish() {
this.subscribes.forEach(subscribe =>{
subscribe.update();
})
},
subscribe(sub) {
this.subscribes.push(sub)
}
}
var subscribe = {
update() {
console.log('update')
},
subscribe(pubsub) {
pubsub.subscribe(this);
}
}
subscribe.subscribe(pubsub)
publisher.publish(pubsub)
感謝-> https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/25
看代碼就很容易了解了。轉一下java實作也不難,這裡就偷個懶了~