什么是觀察者模式?它觀察的是什么?
觀察者模式是計(jì)算機(jī)編程領(lǐng)域比較常見(jiàn)的一種模式,那么,什么是觀察者模式?它是如何工作的?這篇文章我們將深入探討觀察者模式的定義、結(jié)構(gòu)、優(yōu)缺點(diǎn)、適用場(chǎng)景以及代碼實(shí)現(xiàn)等方面。
1. 觀察者模式是什么?
觀察者設(shè)計(jì)模式(Observer Pattern)是一種行為型設(shè)計(jì)模式,它定義了一種一對(duì)多的依賴(lài)關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。當(dāng)主題對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴(lài)于它的觀察者對(duì)象都會(huì)得到通知并自動(dòng)更新。這種模式常用于事件處理系統(tǒng)。
2. 觀察者模式的組成部分
觀察者模式主要由以下幾個(gè)部分組成:
- 主題(Subject):它是一個(gè)接口或者抽象類(lèi),定義了注冊(cè)、注銷(xiāo)和通知觀察者的方法。
- 具體主題(Concrete Subject):具體主題類(lèi)實(shí)現(xiàn)了主題接口,維護(hù)一個(gè)觀察者列表,當(dāng)自身狀態(tài)改變時(shí),通知所有觀察者。
- 觀察者(Observer):它是一個(gè)接口或者抽象類(lèi),定義了更新自身的方法。
- 具體觀察者(Concrete Observer):具體觀察者類(lèi)實(shí)現(xiàn)了觀察者接口,以便在接收到通知時(shí)自身狀態(tài)能與主題同步。
3. 工作流程
從整體上看,觀察者模式的工作流程包含如下步驟:
- 注冊(cè)觀察者:觀察者通過(guò)調(diào)用主題的注冊(cè)方法(如 attach())將自己注冊(cè)到主題中。
- 狀態(tài)改變:主題的狀態(tài)或數(shù)據(jù)發(fā)生變化(例如,屬性值改變)。
- 通知觀察者:主題執(zhí)行通知方法(如 notify()),遍歷所有注冊(cè)的觀察者。調(diào)用每個(gè)觀察者的更新方法(如 update()),并傳遞必要的數(shù)據(jù)。
- 觀察者更新:觀察者接收到通知后,根據(jù)主題的當(dāng)前狀態(tài)進(jìn)行相應(yīng)的處理(如更新自己的狀態(tài)或執(zhí)行操作)。
為了更好地理解觀察者模式的工作原理,下面我們通過(guò)一個(gè)簡(jiǎn)單的Java示例,演示如何實(shí)現(xiàn)觀察者模式。
import java.util.ArrayList;
import java.util.List;
// 觀察者接口
interface Observer {
void update(String message);
}
// 具體觀察者
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
// 主題接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具體主題
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
// 測(cè)試類(lèi)
public class ObserverPatternDemo {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setMessage("Hello, Observers!");
subject.setMessage("Another message");
subject.removeObserver(observer1);
subject.setMessage("Observer 1 should not receive this");
}
}
代碼詳細(xì)解析
(1) 主題接口與具體主題:
- Subject接口定義了注冊(cè)、移除和通知觀察者的方法。
- ConcreteSubject實(shí)現(xiàn)了Subject接口,并維護(hù)一個(gè)觀察者列表。當(dāng)其狀態(tài)改變時(shí),通過(guò)調(diào)用notifyObservers()方法通知所有觀察者。
(2) 觀察者接口與具體觀察者:
- Observer接口定義了update方法,當(dāng)主題狀態(tài)改變時(shí),主題會(huì)調(diào)用此方法。
- ConcreteObserver實(shí)現(xiàn)了Observer接口,并在update方法中定義了當(dāng)收到通知時(shí)的具體行為。
(3) 通知機(jī)制:
- 當(dāng)ConcreteSubject的狀態(tài)通過(guò)setMessage方法改變時(shí),它會(huì)調(diào)用notifyObservers()方法,向所有的觀察者發(fā)送更新通知。
- 觀察者通過(guò)實(shí)現(xiàn)update方法來(lái)處理這些通知。
4. 優(yōu)缺點(diǎn)
(1) 優(yōu)點(diǎn)
- 松耦合:觀察者模式實(shí)現(xiàn)了對(duì)象之間的松耦合,觀察者和主題之間并不需要明確的依賴(lài)關(guān)系,只通過(guò)接口來(lái)交互。這使得系統(tǒng)更具擴(kuò)展性。
- 動(dòng)態(tài)交互:可以在運(yùn)行時(shí)添加或移除觀察者,靈活性強(qiáng)。這對(duì)于需要?jiǎng)討B(tài)調(diào)整的程序非常有用。
- 多種訂閱方式:不同的觀察者可以對(duì)同一主題訂閱不同的條件,以應(yīng)對(duì)復(fù)雜的業(yè)務(wù)邏輯。
(2) 缺點(diǎn)
- 通知機(jī)制開(kāi)銷(xiāo):在主題狀態(tài)改變時(shí),需要通知所有觀察者,這可能導(dǎo)致性能問(wèn)題,尤其是在觀察者數(shù)量較多時(shí)。
- 觀察者管理復(fù)雜:觀察者的管理可能會(huì)變得復(fù)雜,特別是在大量觀察者需要注銷(xiāo)的情況下,需要確保所有觀察者的狀態(tài)一致性。
- 隱式依賴(lài):雖然觀察者模式松耦合,但是觀察者和主題之間仍然存在隱式依賴(lài)關(guān)系,可能導(dǎo)致在系統(tǒng)分析和維護(hù)時(shí)的復(fù)雜性增加。
5. 總結(jié)
這篇文章,我們分析了觀察者模式以及實(shí)現(xiàn)的示例代碼,它是一種常用的設(shè)計(jì)模式,適用于需要對(duì)一個(gè)對(duì)象的狀態(tài)變化做出響應(yīng)的場(chǎng)景。通過(guò)使用觀察者模式,可以實(shí)現(xiàn)對(duì)象之間的松耦合,提高系統(tǒng)的靈活性和可維護(hù)性。