《Head First 設計模式》 學習筆記,碼雲同步更新中
如有錯誤或不足之處,請一定指出,謝謝~
往期回顧
觀察者模式
- 定義:
- 定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,他的所有依賴者都會收到通知並自動更新
- 結構:
- Subject:主題接口
- ConcreteSubject:具體主題
- Observer:觀察者接口
- ConcreteObserver:具體觀察者
- 優點:
- 具體主題和具體觀察者之間爲鬆耦合關係
- 符合“開閉原則”
- 缺點:
- 沒有相應的機制使觀察者知道主題是如何發生變化的
- 如果觀察者之間存在循環調用,會導致系統崩潰,需要特別注意
- 適用範圍:
- 一個對象的改變需要觸發其他多個對象的改變,但不知道具體有多少需要改變的對象,降低對象間的耦合
- 一個對象需要通知很多其他對象,但不需要知道他們是誰
- 與發佈-訂閱模式的區別
- 發佈-訂閱模式中,發佈者不直接和訂閱者通信,他們甚至不知道對方的存在。他們通過第三方信息中介進行通信
- 觀察者模式大多是同步的,而發佈-訂閱模式大多是異步的(消息隊列)
- 其他:
- 在另一個例子中:氣象臺(主題)發佈實時數據(間隔很短,假設1秒一次),
佈告板(觀察者)顯示氣溫(有可能實時,也有可能每天一次,或者統計月平均數據)。
這種情況下觀察者需要將接收到的數據緩存下來,然後在各自設定的時間對外展示。 - 在JDK的java.util包中,提供了Observable類以及Observer接口,它們構成了Java語言對觀察者模式的支持。
- 在另一個例子中:氣象臺(主題)發佈實時數據(間隔很短,假設1秒一次),
- 案例:
- 線上商城客戶下單付款後,需要執行一系列業務邏輯,隨時有可能增加或刪去
- 發送短信
- 累計積分
- 購物節活動贈送小禮品
- 原有實現:在付款成功後的方法中增加相關代碼,等到不需要時再刪除代碼。
- 問題:反覆增刪改付款核心邏輯,易出錯,難維護。
- 觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,他的所有依賴者都會收到通知並自動更新
- 創建觀察者(通知)接口、被觀察者(主題)接口
- 分別實現這兩個接口——訂單付款主題,返現觀察者,發送信息觀察者等等…
- 創建訂單付款後處理器,可交由Spring管理,通過配置文件配置觀察者向主題進行註冊
- 在原訂單付款後方法中,掉用處理器方法,讓主題發出通知,各觀察者接收通知執行各自邏輯
- 線上商城客戶下單付款後,需要執行一系列業務邏輯,隨時有可能增加或刪去
- 代碼:
/**
* 主題
*/
public interface Subject<T> {
/**
* 觀察者註冊
* @param o
*/
void registerObserver(Observer o);
/**
* 觀察者退出
* @param o
*/
void removeObserver(Observer o);
/**
* 發出通知
* @param t
*/
void notifyObservers(T t);
}
/**
* 訂單支付 主題
**/
public class OrderPaidSubject implements Subject<Order> {
/**
* 觀察者名單
*/
private ArrayList<Observer> observerList;
public OrderPaidSubject() {
observerList = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observerList.add(o);
}
@Override
public void removeObserver(Observer o) {
observerList.remove(o);
}
/**
* 遍歷觀察者名單發送通知
* @param order
*/
@Override
public void notifyObservers(Order order) {
observerList.forEach(observer -> observer.update(order));
}
}
/**
* 觀察者
*/
public interface Observer<T> {
/**
* 接收通知
*/
void update(T t);
}
/**
* 返現觀察者
**/
public class CashBackOB implements Observer<Order> {
@Override
public void update(Order order) {
System.out.println("返現5元,訂單編號:" + order.getOrderNo());
}
}
/**
* 發送短信觀察者
**/
public class SendMsgOB implements Observer<Order> {
@Override
public void update(Order order) {
System.out.println("發送短信,訂單編號:" + order.getOrderNo());
}
}
/**
* 訂單
**/
@Data
public class Order {
private Integer orderId;
private String orderNo;
}
/**
* 訂單支付後處理
**/
public class OrderPaidHandler {
private OrderPaidSubject orderPaidSubject;
public OrderPaidHandler() {
orderPaidSubject = new OrderPaidSubject();
// 可改造爲 通過配置文件 註冊
orderPaidSubject.registerObserver(new CashBackOB());
orderPaidSubject.registerObserver(new SendMsgOB());
}
public void orderIsPaid(Order order) {
orderPaidSubject.notifyObservers(order);
}
}
/**
* 測試類
**/
public class Test {
public static void main(String[] args) {
OrderPaidHandler orderPaidHandler = new OrderPaidHandler();
Order order = new Order();
order.setOrderId(1);
order.setOrderNo("01012254");
orderPaidHandler.orderIsPaid(order);
}
}
結果:
返現5元,訂單編號:01012254
發送短信,訂單編號:01012254