行為型模式涉及到算法和物件間職責的分配,行為模式描述了物件和類的模式,以及它們之間的通信模式,行為模式刻劃了在程式運行時難以追蹤的複雜的控制流可分為行為類模式和行為物件模式。
- 行為類模式使用繼承機制在類間分派行為。
- 行為物件模式使用物件聚合來分配行為。一些行為物件模式描述了一組對等的物件怎樣相互協作以完成其中任何一個物件都無法單獨完成的任務。
職責鏈模式(Chain of Responsibility)#
為了避免請求發送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一物件記住其下一個物件的引用而連成一條鏈;當有請求發生時,可將請求沿著這條鏈傳遞,直到有物件處理它為止。
結構#
- 抽象處理者(Handler):定義處理請求的介面(如
handleRequest()
),並持有下一個處理者的引用。 - 具體處理者(Concrete Handler): 實現處理邏輯,決定是否處理請求或傳遞。
- 客戶端(Client): 創建處理鏈並觸發請求。
實現
// 抽象處理者
public abstract class Approver {
protected Approver nextApprover;
public void setNext(Approver next) { this.nextApprover = next; }
public abstract void handleRequest(LeaveRequest request);
}
// 具體處理者:組長
public class GroupLeader extends Approver {
@Override
public void handleRequest(LeaveRequest request) {
if (request.getDays() <= 2) {
System.out.println("組長批准請假");
} else if (nextApprover != null) {
nextApprover.handleRequest(request); // 傳遞請求
}
}
}
// 客戶端構建鏈
Approver groupLeader = new GroupLeader();
Approver manager = new Manager();
groupLeader.setNext(manager);
groupLeader.handleRequest(new LeaveRequest("張三", 3)); // 轉經理處理
迭代器模式#
迭代器模式是一種行為型設計模式,它提供了一種統一的方式來訪問集合物件中的元素,而不是暴露集合內部的表示方式。簡單地說,就是將遍歷集合的責任封裝到一個單獨的物件中,我們可以按照特定的方式訪問集合中的元素。(聽不懂,斯密達)
將類組成數組迭代與迭代器的區別:迭代器模式通過抽象遍歷邏輯和解耦數據結構,提供了更高的靈活性(不同的遍歷策略:分頁、並行)和擴展性,尤其適合需要隱藏內部實現、支持多樣化遍歷策略的場景。通過泛型(如Iterator<T>
)保證類型安全,同時為不同集合(List
、Set
)提供統一介面。例如,Java 的Iterable
介面允許for-each
循環兼容所有集合。而數組直接迭代在簡單、固定數據結構的場景中更具性能優勢。
CS61B 11. Inheritance IV: Iterators, Object Methods
應用
遍歷音樂播放列表:當我們在手機或電腦上播放音樂時,通常會創建一個播放列表。播放列表可以被視為一個集合,每首歌曲可以被視為集合中的一個元素。使用迭代器模式,我們可以通過迭代器物件逐個訪問播放列表中的歌曲,進行播放、暫停或切歌等操作。
迭代器模式的組成#
- 抽象迭代器(Iterator):定義了遍歷聚合物件所需的方法,包括 hashNext () 和 next () 方法等,用於遍歷聚合物件中的元素。
- 具體迭代器(Concrete Iterator):它是實現迭代器介面的具體實現類,負責具體的遍歷邏輯。它保存了當前遍歷的位置信息,並可以根據需要向前或向後遍歷集合元素。
- 抽象聚合器(Aggregate): 一般是一個介面,提供一個 iterator () 方法,例如 java 中的 Collection 介面,List 介面,Set 介面等。
- 具體聚合器(ConcreteAggregate):就是抽象容器的具體實現類,比如 List 介面的有序列表實現 ArrayList,List 介面的鏈表實現 LinkList,Set 介面的哈希列表的實現 HashSet 等。
實現#
設計模式第 16 講 —— 迭代器模式(Iterator)-CSDN 博客
狀態模式#
允許物件在內部狀態改變時,改變它的行為 。 將不同的狀 隔離;每個狀態都是一個單獨的類 。
核心角色#
- 上下文(Context):維護當前狀態引用。
- 抽象狀態(State):聲明狀態行為的介面。
- 具體狀態(Concrete State):實現特定狀態下的行為,並可能觸發狀態轉換。
實現#
// 抽象狀態介面:訂單狀態行為契約 (參考網頁2[2](@ref)和網頁8[8](@ref))
public interface OrderState {
void pay(OrderContext context); // 支付操作
void cancel(OrderContext context); // 取消訂單
void ship(OrderContext context); // 發貨操作
void refund(OrderContext context); // 申請退款
void confirmReceipt(OrderContext context); // 確認收貨
}
// 待支付
public class PendingPaymentState implements OrderState {
@Override
public void pay(OrderContext context) {
System.out.println("✅ 支付成功,訂單進入已支付狀態");
context.setState(new PaidState());
}
@Override
public void cancel(OrderContext context) {
System.out.println("❌ 訂單已取消");
context.setState(new CanceledState());
}
// 其他操作禁止(參考網頁8的狀態約束[8](@ref))
@Override
public void ship(OrderContext context) {
throw new IllegalStateException("待支付訂單不能發貨");
}
// ... 類似實現其他方法的禁止邏輯
}
// 已支付
public class PaidState implements OrderState {
@Override
public void ship(OrderContext context) {
System.out.println("🚚 商品已發貨");
context.setState(new ShippedState());
}
@Override
public void refund(OrderContext context) {
System.out.println("🔄 退款申請受理中");
context.setState(new RefundingState());
}
// 禁止重複支付(參考網頁3的狀態轉換[3](@ref))
@Override
public void pay(OrderContext context) {
throw new IllegalStateException("已支付訂單不能重複付款");
}
}
// 已發貨
public class ShippedState implements OrderState {
@Override
public void confirmReceipt(OrderContext context) {
System.out.println("🎁 確認收貨,交易完成");
context.setState(new CompletedState());
}
@Override
public void refund(OrderContext context) {
System.out.println("📦 發起退貨流程");
context.setState(new RefundingState());
}
}
// 上下文類 (訂單主體)
public class OrderContext {
private OrderState currentState;
private String orderId;
public OrderContext() {
this.currentState = new PendingPaymentState(); // 初始狀態 待支付
this.orderId = UUID.randomUUID().toString();
}
// 狀態轉換入口(參考網頁2的TransitionTo設計[2](@ref))
public void setState(OrderState state) {
System.out.printf("【狀態變更】%s → %s%n",
currentState.getClass().getSimpleName(),
state.getClass().getSimpleName());
this.currentState = state;
}
// 委託操作到當前狀態(參考網頁3的上下文設計[3](@ref))
public void pay() { currentState.pay(this); }
public void cancel() { currentState.cancel(this); }
// ... 其他操作委託方法
}
// 客戶端調用示例
public class Client {
public static void main(String[] args) {
OrderContext order = new OrderContext();
order.pay(); // ✅ 正常支付
order.ship(); // ✅ 發貨操作
order.pay(); // ❌ 抛出 IllegalStateException
try {
order.cancel(); // ❌ 已發貨訂單不可取消
} catch (Exception e) {
System.out.println("操作失敗: " + e.getMessage());
}
}
}
模板方法模式#
Java 設計模式 —— 模板方法模式【Template Method Pattern】_java 模板模式 - CSDN 博客
在一個抽象類公開定義了執行它的方法的模板。它的子類可以按需要重寫方法實現,但調用將以抽象類中定義的方式進行。簡單說,模板方法模式,定義一個操作中的算法的骨架,而將一些步驟延遲到子類中,使得子類可以不改變一個算法的結構,就可以重定義該算法的某些特定步驟,這種類型的設計模式屬於行為型模式。核心思想是 “封裝不變,擴展可變”
結構
-
抽象類
- 模板方法:定義算法骨架(通常用
final
修飾防止子類覆蓋),包含基本方法和抽象方法。 - 基本方法:通用步驟的實現(如
boilWater()
燒水),可直接繼承或提供默認實現。 - 抽象方法:必須由子類實現的步驟(如
brew()
沖泡咖啡) - 鉤子方法(Hook Method):可選步驟(如
customerWantsCondiments()
是否加配料),子類可選擇性重寫。
- 模板方法:定義算法骨架(通常用
-
具體子類
- 繼承抽象類,實現抽象方法或重寫鉤子方法,提供具體邏輯(如
Americano
實現咖啡沖泡細節)。
- 繼承抽象類,實現抽象方法或重寫鉤子方法,提供具體邏輯(如
實現
// 抽象類
public abstract class CoffeeMaker {
// 模板方法(定義算法骨架)
public final void makeCoffee() {
boilWater();
brew();
pourInCup();
if (needCondiments()) {
addCondiments();
}
}
// 基本方法(通用步驟)
private void boilWater() { System.out.println("燒水"); }
// 抽象方法(必須由子類實現)
protected abstract void brew();
// 鉤子方法(可選步驟)
protected boolean needCondiments() { return true; }
protected void addCondiments() {} // 默認空實現
}
// 具體子類
public class Americano extends CoffeeMaker {
@Override
protected void brew() { System.out.println("沖泡美式咖啡"); }
@Override
protected boolean needCondiments() { return false; } // 不添加配料
}
策略模式#
策略模式(Strategy Pattern)定義了一組同類型的算法,在不同的類中封裝起來,每種算法可以根據當前場景相互替換,從而使算法的變化獨立於使用它們的客戶端(即算法的調用者)。
- 算法封裝以互相替換
- 使算法獨立於使用算法的用戶
以用戶支付時不同的支付方式為例,正常情況下需要判斷用戶使用哪種支付方式跳轉至對應的支付頁面。這樣的缺點也很明顯:
- 擴展性差
- 之後修改任何邏輯,當前方法都會被修改
超過 3 層的 if-else 的邏輯判斷代碼可以使用衛語句、策略模式、狀態模式等來實現。
策略模式主要通過創建介面 **(定義策略介面),並對其加以不同的實現(實現策略介面)** 來提高代碼的擴展性。
介面類只負責業務策略的定義,每個策略的具體實現單獨放在實現類中,工廠類 Factory 只負責獲取具體實現類,而具體調用代碼則負責業務邏輯的編排。這些實現用到了面向介面而非實現編程,滿足了職責單一、開閉原則,從而達到了功能上的高內聚低耦合、提高了可維護性、擴展性以及代碼的可讀性。
工廠模式創建
public class PaymentFactory {
private static final Map<PayTypeEnum, Payment> payStrategies = new HashMap<>();
static {
payStrategies.put(PayTypeEnum.WX, new WxPayment());
payStrategies.put(PayTypeEnum.ALIPAY, new AlipayPayment());
payStrategies.put(PayTypeEnum.BANK_CARD, new BankCardPayment());
}
public static Payment getPayment(PayTypeEnum payType) {
if (payType == null) {
throw new IllegalArgumentException("pay type is empty.");
}
if (!payStrategies.containsKey(payType)) {
throw new IllegalArgumentException("pay type not supported.");
}
return payStrategies.get(payType);
}
}
使用
Order order = 訂單信息
PayResult payResult = PaymentFactory.getPayment(payType).pay(order);
if (payResult == PayResult.SUCCESS) {
System.out.println("支付成功");
} else if (payType == 支付寶) {
System.out.println("支付失敗");
}
觀察者模式#
圖說設計模式 — Graphic Design Patterns
觀察者模式是一種軟體設計模式,屬於行為型模式之一。這種模式用於建立一種物件與物件之間的依賴關係,其中 ** 一個物件的狀態發生改變時,所有依賴於它的物件都會得到通知並自動更新。** 在此,發生改變的物件稱為觀察目標,而被通知的物件稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯繫,可以根據需要增加和刪除觀察者,使得系統更易於擴展,這就是觀察者模式的模式動機。
在觀察者模式中,有兩個主要的角色:
- Subject: 目標(主題)
- ConcreteSubject: 具體目標,提供添加、刪除、通知觀察者的方法。當主題的狀態發生變化時,它會遍歷觀察者列表,調用每個觀察者的方法來通知它們。
- Observer: 觀察者
- ConcreteObserver: 具體觀察者,定義了一個更新方法,當主題狀態改變時,所有依賴於該主題的觀察者都會收到通知,並執行相應的操作。
實現
觀察者模式(Observer) Java 實現_java implements observer-CSDN 博客
Subject 抽象主題角色類
public abstract class Subject {
/**
* 用來保存註冊的觀察者物件
*/
private List<Observer> list = new ArrayList<>();
/**
* 註冊觀察者物件
* @param observer 觀察者物件
*/
public void attach(Observer observer) {
list.add(observer);
System.out.println("Attached an observer");
}
/**
* 移除觀察者物件
* @param observer 觀察者物件
*/
public void detach(Observer observer) {
list.remove(observer);
}
/**
* 通知所有註冊的觀察者物件
*/
public void notifyObservers(String newState) {
for (Observer observer : list) {
observer.update(newState);
}
}
}
ConcreteSubject 具體主題
public class ConcreteSubject extends Subject {
private String state;
public String getState() {
return state;
}
public void change(String newState) {
state = newState;
System.out.println("主題狀態為:" + state);
// 狀態發生改變,通知各個觀察者
this.notifyObservers(state);
}
}
Observer 抽象觀察者角色類
public interface Observer {
/**
* 更新介面
* @param state 更新的狀態
*/
void update(String state);
}
ConcreteObserver 具體觀察者角色類
public class ConcreteObserver implements Observer {
// 觀察者狀態
private String observerState;
@Override
public void update(String state) {
/**
* 更新觀察者的狀態,使其與目標的狀態保持一致
*/
observerState = state;
System.out.println("狀態為:" + observerState);
}
}
客戶端類
public class Client {
public static void main(String[] args) {
// 創建主題物件
ConcreteSubject subject = new ConcreteSubject();
// 創建觀察者物件
Observer observer = new ConcreteObserver();
// 將觀察者物件註冊到主題物件上
subject.attach(observer);
// 改變主題物件的狀態
subject.change("new state");
}
}
優點
- 實現表示層和數據邏輯層的分離,並定義了穩定的消息更新傳遞機制,抽象了更新介面,使得可以有各種各樣不同的表示層作為具體觀察者角色。
- 在觀察目標和觀察者之間建立一個抽象的耦合。
- 支持廣播通信。
- 符合 “開閉原則” 的要求。
缺點
- 觀察者眾多時,將所有的觀察者都通知到會花費很多時間。
- 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
- 沒有相應的機制讓觀察者知道所觀察的目標物件是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
應用
凡是涉及到一對一或者一對多的物件交互場景都可以使用觀察者模式。
擴展#
MVC (Model-View-Controller)
MVC 模式是一種架構模式,它包含三個角色:模型 (Model),視圖 (View) 和控制器 (Controller)。觀察者模式可以用來實現 MVC 模式,觀察者模式中的觀察目標就是 MVC 模式中的模型 (Model),而觀察者就是 MVC 中的視圖 (View),控制器 (Controller) 充當兩者之間的中介者 (Mediator)。當模型層的數據發生改變時,視圖層將自動改變其顯示內容。
-
Model:表示應用程序的數據層或業務邏輯層。它負責管理應用程序的狀態,並直接與數據庫或其他持久化存儲交互。
-
View:用戶界面,它顯示數據給用戶並接收用戶的輸入。它通常只與 Controller 通信。
-
Controller:充當 Model 和 View 之間的中介。它接收用戶的輸入(例如通過 HTTP 請求),處理這些輸入(可能涉及調用 Model 的方法),然後決定要顯示哪個 View。
移動開發中的 iOS Swift (UIKit) 和 Android (Activity/Fragment)
MVC、MVP、MVVM 簡介
MVC (Model-View-Controller)
-
Model:表示應用程序的數據層或業務邏輯層。它負責管理應用程序的狀態,並直接與數據庫或其他持久化存儲交互。
-
View:用戶界面,它顯示數據給用戶並接收用戶的輸入。它通常只與 Controller 通信。
-
Controller:充當 Model 和 View 之間的中介。它接收用戶的輸入(例如通過 HTTP 請求),處理這些輸入(可能涉及調用 Model 的方法),然後決定要顯示哪個 View。
移動開發中的 iOS Swift (UIKit) 和 Android (Activity/Fragment)
MVVM (Model-View-ViewModel)
-
Model:如同前兩種模式,負責數據和業務邏輯。
-
View:用戶界面,它通過綁定機制與 ViewModel 進行交互。它不知道 ViewModel 的存在,只關心如何呈現數據。
-
ViewModel:一個連接 Model 和 View 的橋樑。它暴露公共屬性和命令給 View,並且通過數據綁定和命令綁定的方式與 View 互動。ViewModel 不知道具體的 View,因此可以更容易地實現單元測試。
JavaScript 框架如 Vue.js, Angular, React(雖然 React 更傾向於組件化設計,但也可以配合狀態管理庫如 Redux 實現類似 MVVM 的模式)
兩種模式的主要區別為:
1、數據綁定:MVVM 的一個顯著特點就是雙向數據綁定,這使得數據的變化可以自動同步到 UI 上,同時也允許用戶輸入的數據直接反饋到數據模型中。而在 MVC 模式下,這種同步通常需要通過控制器來手動實現。
2、職責分離:雖然 MVC 和 MVVM 都強調了職責分離的原則,但是 MVVM 通過引入 ViewModel 進一步減少了視圖和模型之間的直接依賴,提高了代碼的可測試性和可維護性。
3、視圖與控制器的關係:在 MVC 中,視圖和控制器之間有直接的交互,而 MVVM 中,視圖主要與 ViewModel 交互,這減少了視圖對業務邏輯的直接依賴,使得 UI 設計更加靈活。