Skip to main content

行为型设计模式详解

行为型设计模式关注对象之间的通信机制,解决对象间责任分配和算法封装的问题。这类模式描述对象如何协作完成单个对象无法完成的任务,以及如何分配职责使对象间的耦合度最小。

核心价值

行为型模式 = 对象通信 + 责任分配 + 算法封装 + 松耦合设计

行为型模式概览

行为型设计模式主要包括以下11种模式,各自针对不同的行为交互场景:

模式名称核心意图关键特征典型应用场景
观察者模式定义对象间的一种一对多依赖关系发布-订阅机制、松耦合通知事件处理系统、UI更新、消息推送
策略模式定义一系列算法,使其可以互相替换算法封装、运行时切换支付方式选择、排序算法切换
命令模式将请求封装为对象,支持撤销等操作行为参数化、请求队列事务处理、命令撤销、GUI操作
状态模式允许对象在内部状态改变时改变行为状态驱动行为、状态转换工作流系统、游戏状态管理
责任链模式多个处理对象组成链,依次处理请求动态链构建、请求传递审批流程、异常处理、过滤器
解释器模式定义语言语法表示,并解释其句子语法树构建、规则解析表达式计算、SQL解析、正则表达式
迭代器模式提供顺序访问集合元素的方法遍历与实现分离、内部迭代器集合遍历、数据流处理
中介者模式封装一组对象如何交互中心化通信、多对多解耦聊天室、航空管制、GUI组件交互
备忘录模式在不违反封装的前提下保存对象状态状态捕获、历史回溯编辑器撤销功能、游戏存档
模板方法模式定义算法骨架,允许子类重定义特定步骤算法复用、钩子方法构建流程、数据处理流程
访问者模式将算法与对象结构分离双分派、结构与操作分离复杂对象操作、报表生成

观察者模式 (Observer Pattern)

观察者模式是一种行为设计模式,它定义了对象间的一种一对多依赖关系,使得当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。

  • 当一个对象的状态变化需要通知其他多个对象时
  • 当应用中某些对象需要观察其他对象时,但仅在有限时间内或特定情况下
  • 当对象间存在一对多依赖,而且依赖关系不是永久性的
  • 需要建立一套触发机制的场景

观察者模式结构

观察者模式主要由以下几个角色组成:

  1. 主题(Subject):定义添加、删除和通知观察者的接口
  2. 具体主题(ConcreteSubject):实现主题接口,维护观察者列表,状态变更时通知观察者
  3. 观察者(Observer):定义接收通知时的更新接口
  4. 具体观察者(ConcreteObserver):实现观察者接口,维护与主题的一致性,存储感兴趣的状态

观察者模式实现

下面是一个典型的观察者模式实现:

观察者模式基本实现
java
1// 观察者接口
2public interface Observer {
3 void update(String message);
4}
5
6// 主题接口
7public interface Subject {
8 void attach(Observer observer);
9 void detach(Observer observer);
10 void notifyObservers();
11}
12
13// 具体主题
14public class NewsAgency implements Subject {
15 private List<Observer> observers = new ArrayList<>();
16 private String news;
17
18 @Override
19 public void attach(Observer observer) {
20 observers.add(observer);
21 }
22
23 @Override
24 public void detach(Observer observer) {
25 observers.remove(observer);
26 }
27
28 @Override
29 public void notifyObservers() {
30 for (Observer observer : observers) {
31 observer.update(news);
32 }
33 }
34
35 public void setNews(String news) {
36 this.news = news;
37 notifyObservers();
38 }
39}
40
41// 具体观察者
42public class NewsChannel implements Observer {
43 private String name;
44
45 public NewsChannel(String name) {
46 this.name = name;
47 }
48
49 @Override
50 public void update(String news) {
51 System.out.println(name + " 收到新闻: " + news);
52 }
53}
54
55// 使用示例
56public class ObserverDemo {
57 public static void main(String[] args) {
58 NewsAgency agency = new NewsAgency();
59
60 Observer tv1 = new NewsChannel("CCTV");
61 Observer tv2 = new NewsChannel("BBC");
62 Observer tv3 = new NewsChannel("CNN");
63
64 agency.attach(tv1);
65 agency.attach(tv2);
66 agency.attach(tv3);
67
68 agency.setNews("重大新闻:观察者模式发布!");
69
70 agency.detach(tv2); // BBC退订
71
72 agency.setNews("后续报道:观察者模式运行良好!");
73 }
74}

观察者模式变体

推模型是观察者模式的标准实现,主题将所有状态变化推送给观察者:

java
1// 推模型 - 主题将所有数据推送给观察者
2public interface Observer {
3 void update(String message, LocalDateTime timestamp, String category);
4}
5
6public class ConcreteObserver implements Observer {
7 @Override
8 public void update(String message, LocalDateTime timestamp, String category) {
9 System.out.println("收到消息: " + message);
10 System.out.println("时间: " + timestamp);
11 System.out.println("类别: " + category);
12 }
13}

观察者模式应用实例

java
1// 事件处理系统中的观察者模式
2public interface EventListener {
3 void handleEvent(Event event);
4}
5
6public class UIButton {
7 private List<EventListener> clickListeners = new ArrayList<>();
8
9 public void addClickListener(EventListener listener) {
10 clickListeners.add(listener);
11 }
12
13 public void removeClickListener(EventListener listener) {
14 clickListeners.remove(listener);
15 }
16
17 public void click() {
18 Event event = new Event("click", this);
19 for (EventListener listener : clickListeners) {
20 listener.handleEvent(event);
21 }
22 }
23}
24
25// 具体监听器
26public class SaveButtonListener implements EventListener {
27 @Override
28 public void handleEvent(Event event) {
29 if (event.getType().equals("click")) {
30 System.out.println("保存文档...");
31 saveDocument();
32 }
33 }
34
35 private void saveDocument() {
36 // 保存文档的逻辑
37 }
38}
39
40// 使用示例
41public static void main(String[] args) {
42 UIButton saveButton = new UIButton();
43 saveButton.addClickListener(new SaveButtonListener());
44
45 // 用户点击按钮
46 saveButton.click();
47}

观察者模式与其他模式比较

模式区别组合使用场景
观察者模式 vs 中介者模式观察者模式中观察者知道主题的存在,而中介者模式中组件通过中介者间接通信中介者可以作为观察者实现,或者使用观察者模式监听中介者状态
观察者模式 vs 发布-订阅模式发布-订阅通常有一个事件通道作为中间层,发布者和订阅者互不了解可以使用观察者模式实现发布-订阅模式的核心机制
观察者模式 vs 命令模式命令模式封装请求为对象,观察者模式处理对象间的事件通知命令对象可以作为观察者,在事件发生时执行特定命令

观察者模式实现要点

  1. 线程安全考虑:在多线程环境中,观察者列表和通知机制需要考虑同步问题

    java
    1// 线程安全的观察者列表
    2private final List<Observer> observers =
    3 Collections.synchronizedList(new ArrayList<>());
    4
    5// 或使用并发集合
    6private final CopyOnWriteArrayList<Observer> observers =
    7 new CopyOnWriteArrayList<>();
  2. 防止内存泄漏:弱引用可以防止观察者持有导致的内存泄漏

    java
    1// 使用弱引用存储观察者
    2private final List<WeakReference<Observer>> observers = new ArrayList<>();
    3
    4public void notifyObservers() {
    5 Iterator<WeakReference<Observer>> iterator = observers.iterator();
    6 while (iterator.hasNext()) {
    7 Observer observer = iterator.next().get();
    8 if (observer != null) {
    9 observer.update(this.state);
    10 } else {
    11 // 移除已被垃圾收集的观察者引用
    12 iterator.remove();
    13 }
    14 }
    15}
  3. 异常处理:观察者处理过程中的异常不应影响其他观察者

    java
    1public void notifyObservers() {
    2 for (Observer observer : observers) {
    3 try {
    4 observer.update(this.state);
    5 } catch (Exception e) {
    6 // 记录异常但继续通知其他观察者
    7 logger.error("通知观察者时发生错误", e);
    8 }
    9 }
    10}
观察者模式最佳实践
  • 明确定义观察者和主题的接口,保持关注点分离
  • 考虑使用JDK内置的Observable类和Observer接口
  • 对于复杂系统,考虑使用事件总线或消息中间件实现
  • 避免在观察者的update方法中执行耗时操作
  • 当观察者数量庞大时,考虑使用批处理或异步通知

策略模式 (Strategy Pattern)

策略模式是一种行为设计模式,它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户端。

  • 当需要使用不同变体的算法时
  • 当需要隐藏算法实现细节时
  • 当类中包含许多行为,这些行为以多个条件语句的形式存在
  • 当算法的选择依赖于调用者的上下文时

策略模式结构

策略模式包含以下几个角色:

  1. 策略(Strategy):定义所有支持的算法的公共接口
  2. 具体策略(ConcreteStrategy):实现策略接口的具体算法
  3. 上下文(Context):维护一个策略引用,使用该引用调用具体策略

策略模式实现

下面是一个典型的策略模式实现:

策略模式基本实现
java
1// 策略接口
2public interface PaymentStrategy {
3 void pay(int amount);
4}
5
6// 具体策略A
7public class CreditCardPayment implements PaymentStrategy {
8 private String cardNumber;
9 private String name;
10 private String cvv;
11 private String dateOfExpiry;
12
13 public CreditCardPayment(String cardNumber, String name, String cvv, String dateOfExpiry) {
14 this.cardNumber = cardNumber;
15 this.name = name;
16 this.cvv = cvv;
17 this.dateOfExpiry = dateOfExpiry;
18 }
19
20 @Override
21 public void pay(int amount) {
22 System.out.println(amount + " 元已通过信用卡支付");
23 }
24}
25
26// 具体策略B
27public class PayPalPayment implements PaymentStrategy {
28 private String emailId;
29 private String password;
30
31 public PayPalPayment(String email, String password) {
32 this.emailId = email;
33 this.password = password;
34 }
35
36 @Override
37 public void pay(int amount) {
38 System.out.println(amount + " 元已通过PayPal支付");
39 }
40}
41
42// 具体策略C
43public class WeChatPayment implements PaymentStrategy {
44 private String id;
45
46 public WeChatPayment(String id) {
47 this.id = id;
48 }
49
50 @Override
51 public void pay(int amount) {
52 System.out.println(amount + " 元已通过微信支付");
53 }
54}
55
56// 上下文
57public class ShoppingCart {
58 private PaymentStrategy paymentStrategy;
59
60 public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
61 this.paymentStrategy = paymentStrategy;
62 }
63
64 public void checkout(int amount) {
65 paymentStrategy.pay(amount);
66 }
67}
68
69// 使用示例
70public class StrategyDemo {
71 public static void main(String[] args) {
72 ShoppingCart cart = new ShoppingCart();
73
74 // 用户选择信用卡支付
75 cart.setPaymentStrategy(new CreditCardPayment(
76 "1234567890123456", "张三", "123", "12/25"));
77 cart.checkout(1000);
78
79 // 用户选择PayPal支付
80 cart.setPaymentStrategy(new PayPalPayment("zhangsan@example.com", "password"));
81 cart.checkout(500);
82
83 // 用户选择微信支付
84 cart.setPaymentStrategy(new WeChatPayment("zhangsan123"));
85 cart.checkout(300);
86 }
87}

策略模式变体

使用Java 8函数式接口和Lambda表达式可以简化策略模式的实现:

java
1// 使用函数式接口定义策略
2public interface DiscountStrategy {
3 double applyDiscount(double amount);
4}
5
6public class PriceCalculator {
7 private DiscountStrategy discountStrategy;
8
9 public void setDiscountStrategy(DiscountStrategy discountStrategy) {
10 this.discountStrategy = discountStrategy;
11 }
12
13 public double calculateFinalPrice(double price) {
14 return discountStrategy.applyDiscount(price);
15 }
16}
17
18// 使用Lambda表达式作为策略
19public class FunctionalStrategyDemo {
20 public static void main(String[] args) {
21 PriceCalculator calculator = new PriceCalculator();
22
23 // 无折扣策略
24 calculator.setDiscountStrategy(amount -> amount);
25 System.out.println("原价: " + calculator.calculateFinalPrice(100));
26
27 // 固定金额折扣策略
28 calculator.setDiscountStrategy(amount -> amount - 20);
29 System.out.println("满减20: " + calculator.calculateFinalPrice(100));
30
31 // 百分比折扣策略
32 calculator.setDiscountStrategy(amount -> amount * 0.8);
33 System.out.println("8折优惠: " + calculator.calculateFinalPrice(100));
34
35 // 条件折扣策略
36 calculator.setDiscountStrategy(amount ->
37 amount > 200 ? amount * 0.8 : amount * 0.9);
38 System.out.println("满200打8折,否则9折: " + calculator.calculateFinalPrice(250));
39 }
40}

策略模式应用实例

java
1// 排序策略接口
2public interface SortStrategy<T> {
3 List<T> sort(List<T> dataset);
4}
5
6// 具体排序策略
7public class QuickSortStrategy<T extends Comparable<T>> implements SortStrategy<T> {
8 @Override
9 public List<T> sort(List<T> dataset) {
10 // 快速排序实现
11 System.out.println("使用快速排序");
12 List<T> result = new ArrayList<>(dataset);
13 // 排序逻辑...
14 return result;
15 }
16}
17
18public class MergeSortStrategy<T extends Comparable<T>> implements SortStrategy<T> {
19 @Override
20 public List<T> sort(List<T> dataset) {
21 // 归并排序实现
22 System.out.println("使用归并排序");
23 List<T> result = new ArrayList<>(dataset);
24 // 排序逻辑...
25 return result;
26 }
27}
28
29public class BubbleSortStrategy<T extends Comparable<T>> implements SortStrategy<T> {
30 @Override
31 public List<T> sort(List<T> dataset) {
32 // 冒泡排序实现
33 System.out.println("使用冒泡排序");
34 List<T> result = new ArrayList<>(dataset);
35 // 排序逻辑...
36 return result;
37 }
38}
39
40// 上下文类
41public class Sorter<T extends Comparable<T>> {
42 private SortStrategy<T> strategy;
43
44 public void setSortStrategy(SortStrategy<T> strategy) {
45 this.strategy = strategy;
46 }
47
48 public List<T> sort(List<T> dataset) {
49 return strategy.sort(dataset);
50 }
51}
52
53// 基于数据特性自动选择排序策略的增强上下文
54public class SmartSorter<T extends Comparable<T>> {
55 private SortStrategy<T> quickSort = new QuickSortStrategy<>();
56 private SortStrategy<T> mergeSort = new MergeSortStrategy<>();
57 private SortStrategy<T> bubbleSort = new BubbleSortStrategy<>();
58
59 public List<T> sort(List<T> dataset) {
60 // 根据数据大小选择合适的排序算法
61 if (dataset.size() <= 10) {
62 return bubbleSort.sort(dataset);
63 } else if (dataset.size() <= 1000) {
64 return quickSort.sort(dataset);
65 } else {
66 return mergeSort.sort(dataset);
67 }
68 }
69}

策略模式与其他模式比较

模式区别组合使用场景
策略模式 vs 状态模式状态模式允许对象随着状态改变而改变行为,策略模式专注于不同算法的互换策略模式可以用来实现状态模式中的不同状态行为
策略模式 vs 命令模式命令模式封装执行行为的请求,策略模式封装不同的算法实现命令可以使用不同的策略执行请求
策略模式 vs 模板方法模式模板方法使用继承来更改算法的部分内容,策略使用组合来更换整个算法模板方法的钩子方法可以使用策略模式提供不同实现

策略模式实现要点

  1. 上下文和策略的关系:上下文不应过度依赖具体策略的内部细节

  2. 策略的动态选择:基于条件自动选择策略可以提高灵活性

    java
    1public PaymentStrategy chooseStrategy(String paymentType, Map<String, String> paymentDetails) {
    2 switch(paymentType) {
    3 case "CREDIT_CARD":
    4 return new CreditCardPayment(
    5 paymentDetails.get("cardNumber"),
    6 paymentDetails.get("name"),
    7 paymentDetails.get("cvv"),
    8 paymentDetails.get("expiryDate"));
    9 case "PAYPAL":
    10 return new PayPalPayment(
    11 paymentDetails.get("email"),
    12 paymentDetails.get("password"));
    13 case "WECHAT":
    14 return new WeChatPayment(
    15 paymentDetails.get("id"));
    16 default:
    17 throw new IllegalArgumentException("不支持的支付类型");
    18 }
    19}
  3. 策略接口定义:策略接口应该保持简单,仅包含必要方法

    java
    1// 好的做法:接口简洁
    2public interface ValidationStrategy {
    3 boolean validate(String text);
    4}
    5
    6// 避免的做法:接口过于复杂
    7public interface ComplexValidationStrategy {
    8 boolean validate(String text);
    9 boolean validateFormat(String format);
    10 void setValidationRules(List<Rule> rules);
    11 List<String> getValidationErrors();
    12 // 其他不必要的方法...
    13}
  4. 性能考虑:避免频繁创建和切换策略对象

策略模式最佳实践
  • 使用策略模式代替复杂的条件语句
  • 当有多个算法只有微小变化时,考虑使用lambda表达式或匿名类
  • 结合工厂模式可以隐藏客户端对具体策略的直接依赖
  • 策略对象应该是无状态的,以便可以在多个上下文间共享
  • 在合适的情况下使用枚举实现简单的策略模式

命令模式 (Command Pattern)

命令模式是一种行为设计模式,它将请求封装为一个对象,从而可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

  • 需要将操作参数化时
  • 需要将操作放入队列中、操作的执行需要延迟或者操作需要远程执行时
  • 需要支持撤销操作时
  • 需要支持事务操作,将一系列操作作为一个整体执行或回滚
  • 需要实现操作的日志记录、审计或历史记录

命令模式结构

命令模式包含以下几个角色:

  1. 命令(Command):声明执行操作的接口,通常包含execute()方法和可选的undo()方法
  2. 具体命令(ConcreteCommand):定义命令与接收者之间的绑定,实现execute()方法,调用接收者的相关操作
  3. 调用者(Invoker):要求命令执行请求
  4. 接收者(Receiver):知道如何实施与执行请求相关的操作
  5. 客户端(Client):创建具体命令对象并设置其接收者

命令模式实现

下面是一个命令模式的基本实现:

命令模式基本实现
java
1// 命令接口
2public interface Command {
3 void execute();
4 void undo();
5}
6
7// 接收者
8public class Light {
9 private boolean isOn = false;
10 private String location;
11
12 public Light(String location) {
13 this.location = location;
14 }
15
16 public void turnOn() {
17 isOn = true;
18 System.out.println(location + " 灯已打开");
19 }
20
21 public void turnOff() {
22 isOn = false;
23 System.out.println(location + " 灯已关闭");
24 }
25
26 public boolean isOn() {
27 return isOn;
28 }
29}
30
31// 具体命令
32public class LightOnCommand implements Command {
33 private Light light;
34
35 public LightOnCommand(Light light) {
36 this.light = light;
37 }
38
39 @Override
40 public void execute() {
41 light.turnOn();
42 }
43
44 @Override
45 public void undo() {
46 light.turnOff();
47 }
48}
49
50public class LightOffCommand implements Command {
51 private Light light;
52
53 public LightOffCommand(Light light) {
54 this.light = light;
55 }
56
57 @Override
58 public void execute() {
59 light.turnOff();
60 }
61
62 @Override
63 public void undo() {
64 light.turnOn();
65 }
66}
67
68// 调用者
69public class RemoteControl {
70 private Command command;
71
72 public void setCommand(Command command) {
73 this.command = command;
74 }
75
76 public void pressButton() {
77 command.execute();
78 }
79
80 public void pressUndoButton() {
81 command.undo();
82 }
83}
84
85// 客户端
86public class CommandDemo {
87 public static void main(String[] args) {
88 // 创建接收者
89 Light livingRoomLight = new Light("客厅");
90
91 // 创建命令
92 Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
93 Command livingRoomLightOff = new LightOffCommand(livingRoomLight);
94
95 // 创建调用者
96 RemoteControl remote = new RemoteControl();
97
98 // 执行命令
99 remote.setCommand(livingRoomLightOn);
100 remote.pressButton(); // 打开客厅灯
101
102 remote.setCommand(livingRoomLightOff);
103 remote.pressButton(); // 关闭客厅灯
104
105 remote.pressUndoButton(); // 撤销关灯,灯重新打开
106 }
107}

命令模式变体

宏命令允许将多个命令组合成一个命令:

java
1// 宏命令 - 组合多个命令
2public class MacroCommand implements Command {
3 private List<Command> commands;
4
5 public MacroCommand() {
6 this.commands = new ArrayList<>();
7 }
8
9 public void addCommand(Command command) {
10 commands.add(command);
11 }
12
13 @Override
14 public void execute() {
15 for (Command command : commands) {
16 command.execute();
17 }
18 }
19
20 @Override
21 public void undo() {
22 // 逆序撤销
23 for (int i = commands.size() - 1; i >= 0; i--) {
24 commands.get(i).undo();
25 }
26 }
27}
28
29// 使用宏命令
30public static void main(String[] args) {
31 Light livingRoomLight = new Light("客厅");
32 Light kitchenLight = new Light("厨房");
33
34 Command livingRoomLightOn = new LightOnCommand(livingRoomLight);
35 Command kitchenLightOn = new LightOnCommand(kitchenLight);
36
37 MacroCommand allLightsOn = new MacroCommand();
38 allLightsOn.addCommand(livingRoomLightOn);
39 allLightsOn.addCommand(kitchenLightOn);
40
41 RemoteControl remote = new RemoteControl();
42
43 // 一次性打开所有灯
44 remote.setCommand(allLightsOn);
45 remote.pressButton();
46
47 // 一次性关闭所有灯
48 remote.pressUndoButton();
49}

命令模式应用实例

java
1// 文本编辑器中的命令模式
2public class Document {
3 private StringBuilder content = new StringBuilder();
4
5 public void insert(int position, String text) {
6 if (position <= content.length()) {
7 content.insert(position, text);
8 System.out.println("已插入文本:" + text);
9 }
10 }
11
12 public String delete(int position, int length) {
13 if (position < content.length() && position + length <= content.length()) {
14 String deletedText = content.substring(position, position + length);
15 content.delete(position, position + length);
16 System.out.println("已删除文本:" + deletedText);
17 return deletedText;
18 }
19 return "";
20 }
21
22 public String getContent() {
23 return content.toString();
24 }
25}
26
27public interface EditorCommand extends Command {
28 // Command接口中已定义execute和undo方法
29}
30
31public class InsertCommand implements EditorCommand {
32 private Document document;
33 private int position;
34 private String text;
35
36 public InsertCommand(Document document, int position, String text) {
37 this.document = document;
38 this.position = position;
39 this.text = text;
40 }
41
42 @Override
43 public void execute() {
44 document.insert(position, text);
45 }
46
47 @Override
48 public void undo() {
49 document.delete(position, text.length());
50 }
51}
52
53public class DeleteCommand implements EditorCommand {
54 private Document document;
55 private int position;
56 private int length;
57 private String deletedText; // 用于撤销
58
59 public DeleteCommand(Document document, int position, int length) {
60 this.document = document;
61 this.position = position;
62 this.length = length;
63 }
64
65 @Override
66 public void execute() {
67 deletedText = document.delete(position, length);
68 }
69
70 @Override
71 public void undo() {
72 document.insert(position, deletedText);
73 }
74}
75
76public class Editor {
77 private Document document = new Document();
78 private Stack<EditorCommand> undoStack = new Stack<>();
79 private Stack<EditorCommand> redoStack = new Stack<>();
80
81 public void executeCommand(EditorCommand command) {
82 command.execute();
83 undoStack.push(command);
84 redoStack.clear(); // 执行新命令后清空重做栈
85 }
86
87 public void undo() {
88 if (!undoStack.isEmpty()) {
89 EditorCommand command = undoStack.pop();
90 command.undo();
91 redoStack.push(command);
92 }
93 }
94
95 public void redo() {
96 if (!redoStack.isEmpty()) {
97 EditorCommand command = redoStack.pop();
98 command.execute();
99 undoStack.push(command);
100 }
101 }
102
103 public String getContent() {
104 return document.getContent();
105 }
106}
107
108// 使用示例
109public static void main(String[] args) {
110 Editor editor = new Editor();
111
112 // 插入文本
113 editor.executeCommand(new InsertCommand(editor.document, 0, "Hello, "));
114 editor.executeCommand(new InsertCommand(editor.document, 7, "World!"));
115
116 System.out.println("当前内容: " + editor.getContent()); // Hello, World!
117
118 // 删除部分文本
119 editor.executeCommand(new DeleteCommand(editor.document, 7, 6));
120
121 System.out.println("删除后: " + editor.getContent()); // Hello, !
122
123 // 撤销删除
124 editor.undo();
125 System.out.println("撤销后: " + editor.getContent()); // Hello, World!
126
127 // 重做删除
128 editor.redo();
129 System.out.println("重做后: " + editor.getContent()); // Hello, !
130}

命令模式与其他模式比较

模式区别组合使用场景
命令模式 vs 策略模式命令模式关注的是请求的封装,策略模式关注的是算法的封装命令可以使用不同策略执行请求
命令模式 vs 备忘录模式命令可以存储系统状态的变化过程,备忘录存储的是系统在某一时刻的完整状态可以使用备忘录模式来存储命令执行前的状态
命令模式 vs 原型模式命令对象可以通过克隆来创建副本通过原型模式复制命令对象以支持命令的重用

命令模式实现要点

  1. 智能命令与简单命令

    • 简单命令只负责调用接收者的方法
    • 智能命令自己包含业务逻辑,不依赖接收者
  2. 命令参数化

    java
    1// 参数化命令
    2public class ParameterizedCommand implements Command {
    3 private Receiver receiver;
    4 private Object[] parameters;
    5
    6 public ParameterizedCommand(Receiver receiver, Object... parameters) {
    7 this.receiver = receiver;
    8 this.parameters = parameters;
    9 }
    10
    11 @Override
    12 public void execute() {
    13 // 根据参数执行不同操作
    14 receiver.action(parameters);
    15 }
    16
    17 @Override
    18 public void undo() {
    19 // 撤销操作
    20 }
    21}
  3. 命令序列化

    java
    1// 可序列化命令,支持持久化
    2public class SerializableCommand implements Command, Serializable {
    3 private static final long serialVersionUID = 1L;
    4 private transient Receiver receiver; // transient表示不序列化此字段
    5 private String actionName;
    6 private Map<String, Serializable> parameters;
    7
    8 // 构造方法和execute/undo实现
    9 // ...
    10
    11 // 保存命令到文件
    12 public static void saveCommand(Command command, String filename) throws IOException {
    13 try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {
    14 out.writeObject(command);
    15 }
    16 }
    17
    18 // 从文件加载命令
    19 public static Command loadCommand(String filename) throws IOException, ClassNotFoundException {
    20 try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {
    21 return (Command) in.readObject();
    22 }
    23 }
    24}
  4. 命令模式与函数式编程

    java
    1// 使用函数式接口
    2@FunctionalInterface
    3public interface ActionCommand {
    4 void execute();
    5
    6 // Java 8默认方法
    7 default ActionCommand andThen(ActionCommand after) {
    8 return () -> {
    9 this.execute();
    10 after.execute();
    11 };
    12 }
    13}
    14
    15// 使用示例
    16public static void main(String[] args) {
    17 Light light = new Light("客厅");
    18
    19 ActionCommand turnOn = light::turnOn;
    20 ActionCommand turnOff = light::turnOff;
    21
    22 // 组合命令
    23 ActionCommand flashLight = turnOn.andThen(turnOff).andThen(turnOn).andThen(turnOff);
    24
    25 // 执行命令
    26 flashLight.execute();
    27}
命令模式最佳实践
  • 为命令定义清晰的生命周期:创建、执行、撤销和销毁
  • 考虑命令对象的可重用性,避免重复创建相同的命令
  • 对于复杂操作,使用宏命令组合多个命令
  • 在需要持久化、远程执行或延迟执行操作时,考虑使用命令模式
  • 命令模式特别适合实现撤销/重做、事务处理和操作日志

状态模式 (State Pattern)

状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为,使对象看起来好像修改了它的类。状态模式是对象行为随状态改变而改变的场景的解决方案。

  • 对象的行为取决于它的状态,且必须在运行时根据状态改变其行为
  • 代码中包含大量与对象状态有关的条件语句,如多个if-else或switch-case
  • 状态转换规则复杂且频繁变化
  • 需要消除"状态判断"的条件语句时

状态模式结构

状态模式包含以下几个角色:

  1. 上下文(Context):维护一个对当前状态对象的引用,并将与状态相关的操作委托给当前状态对象
  2. 状态(State):定义一个接口,封装与上下文的特定状态相关的行为
  3. 具体状态(ConcreteState):实现状态接口,提供与上下文特定状态相关的行为

状态模式实现

下面是一个典型的状态模式实现:

状态模式基本实现
java
1// 状态接口
2public interface State {
3 void handle(Context context);
4 String getStateName();
5}
6
7// 具体状态A
8public class ConcreteStateA implements State {
9 @Override
10 public void handle(Context context) {
11 System.out.println("当前在状态A,处理完毕后切换到状态B");
12 context.setState(new ConcreteStateB());
13 }
14
15 @Override
16 public String getStateName() {
17 return "State A";
18 }
19}
20
21// 具体状态B
22public class ConcreteStateB implements State {
23 @Override
24 public void handle(Context context) {
25 System.out.println("当前在状态B,处理完毕后切换到状态A");
26 context.setState(new ConcreteStateA());
27 }
28
29 @Override
30 public String getStateName() {
31 return "State B";
32 }
33}
34
35// 上下文
36public class Context {
37 private State currentState;
38
39 public Context() {
40 // 默认状态
41 currentState = new ConcreteStateA();
42 }
43
44 public void setState(State state) {
45 this.currentState = state;
46 System.out.println("状态变为: " + state.getStateName());
47 }
48
49 public void request() {
50 currentState.handle(this);
51 }
52}
53
54// 客户端
55public class StatePatternDemo {
56 public static void main(String[] args) {
57 Context context = new Context();
58
59 context.request(); // A -> B
60 context.request(); // B -> A
61 context.request(); // A -> B
62 }
63}

状态模式变体

状态自身决定下一个状态,适合状态转换逻辑复杂的场景:

java
1// 状态接口
2public interface State {
3 void handle(Context context);
4}
5
6// 具体状态实现,自己负责状态转换
7public class PlayingState implements State {
8 @Override
9 public void handle(Context context) {
10 System.out.println("播放中:可以暂停或停止");
11
12 // 模拟用户点击暂停按钮
13 if (userClickedPause()) {
14 context.setState(new PausedState());
15 }
16
17 // 模拟播放结束
18 if (playbackFinished()) {
19 context.setState(new StoppedState());
20 }
21 }
22}

状态模式应用实例

java
1// 订单状态管理中的状态模式
2public interface OrderState {
3 void processOrder(Order order);
4 void cancelOrder(Order order);
5 void payOrder(Order order);
6 void shipOrder(Order order);
7 void deliverOrder(Order order);
8}
9
10// 新建订单状态
11public class NewOrderState implements OrderState {
12 @Override
13 public void processOrder(Order order) {
14 System.out.println("订单已创建,等待付款");
15 }
16
17 @Override
18 public void cancelOrder(Order order) {
19 System.out.println("取消新订单");
20 order.setState(new CancelledOrderState());
21 }
22
23 @Override
24 public void payOrder(Order order) {
25 System.out.println("订单已付款");
26 order.setState(new PaidOrderState());
27 }
28
29 @Override
30 public void shipOrder(Order order) {
31 System.out.println("错误:未付款订单不能发货");
32 }
33
34 @Override
35 public void deliverOrder(Order order) {
36 System.out.println("错误:未发货订单不能交付");
37 }
38}
39
40// 已付款订单状态
41public class PaidOrderState implements OrderState {
42 @Override
43 public void processOrder(Order order) {
44 System.out.println("订单已付款,等待发货");
45 }
46
47 @Override
48 public void cancelOrder(Order order) {
49 System.out.println("取消已付款订单,需要退款");
50 order.setState(new CancelledOrderState());
51 // 处理退款逻辑
52 }
53
54 @Override
55 public void payOrder(Order order) {
56 System.out.println("错误:订单已支付");
57 }
58
59 @Override
60 public void shipOrder(Order order) {
61 System.out.println("订单已发货");
62 order.setState(new ShippedOrderState());
63 }
64
65 @Override
66 public void deliverOrder(Order order) {
67 System.out.println("错误:未发货订单不能交付");
68 }
69}
70
71// 已发货订单状态
72public class ShippedOrderState implements OrderState {
73 @Override
74 public void processOrder(Order order) {
75 System.out.println("订单正在运送中");
76 }
77
78 @Override
79 public void cancelOrder(Order order) {
80 System.out.println("错误:已发货订单不能取消");
81 }
82
83 @Override
84 public void payOrder(Order order) {
85 System.out.println("错误:订单已支付");
86 }
87
88 @Override
89 public void shipOrder(Order order) {
90 System.out.println("错误:订单已发货");
91 }
92
93 @Override
94 public void deliverOrder(Order order) {
95 System.out.println("订单已交付");
96 order.setState(new DeliveredOrderState());
97 }
98}
99
100// 已交付订单状态
101public class DeliveredOrderState implements OrderState {
102 // 实现方法...
103}
104
105// 已取消订单状态
106public class CancelledOrderState implements OrderState {
107 // 实现方法...
108}
109
110// 订单上下文
111public class Order {
112 private String orderNumber;
113 private OrderState state;
114
115 public Order(String orderNumber) {
116 this.orderNumber = orderNumber;
117 this.state = new NewOrderState();
118 }
119
120 public void setState(OrderState state) {
121 this.state = state;
122 }
123
124 public void processOrder() {
125 state.processOrder(this);
126 }
127
128 public void cancelOrder() {
129 state.cancelOrder(this);
130 }
131
132 public void payOrder() {
133 state.payOrder(this);
134 }
135
136 public void shipOrder() {
137 state.shipOrder(this);
138 }
139
140 public void deliverOrder() {
141 state.deliverOrder(this);
142 }
143}
144
145// 使用示例
146public static void main(String[] args) {
147 Order order = new Order("ORD-12345");
148 order.processOrder(); // 订单已创建,等待付款
149
150 order.payOrder(); // 订单已付款
151 order.processOrder(); // 订单已付款,等待发货
152
153 order.shipOrder(); // 订单已发货
154 order.processOrder(); // 订单正在运送中
155
156 order.deliverOrder(); // 订单已交付
157}

状态模式与其他模式比较

模式区别组合使用场景
状态模式 vs 策略模式状态模式关注对象状态变化引起的行为变化,策略模式专注于不同算法的互换可以使用策略模式来实现不同状态下的不同算法
状态模式 vs 命令模式命令模式封装执行行为的请求,策略模式封装不同的算法实现可以根据当前状态选择不同的命令对象
状态模式 vs 备忘录模式状态模式改变对象行为,备忘录模式保存历史状态可以用备忘录记录状态对象的状态,实现状态恢复

状态模式实现要点

  1. 谁来负责状态转换:状态模式有两种实现方式:

    • 上下文驱动:状态转换逻辑由上下文控制
    • 状态自驱动:状态转换逻辑由状态类自身控制
  2. 状态共享:如果状态不包含内部状态,可以将状态对象设计为共享的:

    java
    1// 状态对象共享
    2public class Context {
    3 // 静态共享状态对象
    4 private static final State STATE_A = new ConcreteStateA();
    5 private static final State STATE_B = new ConcreteStateB();
    6
    7 private State currentState = STATE_A;
    8
    9 public void setState(State state) {
    10 this.currentState = state;
    11 }
    12
    13 public void switchToStateA() {
    14 setState(STATE_A);
    15 }
    16
    17 public void switchToStateB() {
    18 setState(STATE_B);
    19 }
    20}
  3. 状态历史记录:记录状态变化历史,支持状态回退:

    java
    1public class ContextWithHistory {
    2 private State currentState;
    3 private Stack<State> history = new Stack<>();
    4
    5 public void setState(State state) {
    6 history.push(currentState);
    7 currentState = state;
    8 }
    9
    10 public void undo() {
    11 if (!history.isEmpty()) {
    12 currentState = history.pop();
    13 }
    14 }
    15}
  4. 状态转换表:使用状态转换表管理复杂的状态转换规则:

    java
    1public class StateMachineContext {
    2 private Map<StateEvent, State> stateTransitionTable = new HashMap<>();
    3 private State currentState;
    4
    5 public void registerTransition(State fromState, Event event, State toState) {
    6 StateEvent stateEvent = new StateEvent(fromState, event);
    7 stateTransitionTable.put(stateEvent, toState);
    8 }
    9
    10 public void handleEvent(Event event) {
    11 StateEvent stateEvent = new StateEvent(currentState, event);
    12 State nextState = stateTransitionTable.get(stateEvent);
    13
    14 if (nextState != null) {
    15 currentState = nextState;
    16 }
    17 }
    18}
    19
    20// 复合键:状态+事件
    21public class StateEvent {
    22 private State state;
    23 private Event event;
    24
    25 // 构造函数、equals和hashCode方法...
    26}
状态模式最佳实践
  • 首先识别所有可能的状态和它们之间的转换关系
  • 明确状态转换的触发条件
  • 使用状态图或状态转换表来可视化状态机
  • 对于简单状态机,可以考虑使用枚举实现
  • 对于复杂状态机,将状态转换逻辑放在状态类中
  • 避免在状态类中引入上下文特定的数据,保持状态类的独立性
  • 当状态数量少且状态逻辑简单时,可能使用策略模式更合适

责任链模式 (Chain of Responsibility Pattern)

责任链模式是一种行为设计模式,它为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。请求沿着链传递,直到有一个接收者处理它为止。

  • 有多个对象可以处理同一个请求,但具体由哪个对象处理需要在运行时决定
  • 想要在不明确接收者的情况下向多个对象中的一个提交请求
  • 处理请求的对象集合需要被动态指定
  • 需要按照顺序执行多个处理器的场景

责任链模式结构

责任链模式包含以下几个角色:

  1. 处理者(Handler):定义处理请求的接口,包括设置下一个处理者的方法
  2. 具体处理者(ConcreteHandler):实现处理请求的方法,如果自己无法处理,则将请求转发给后继者
  3. 客户端(Client):创建处理者对象并组织责任链,然后将请求发送给链的第一个处理者

责任链模式实现

下面是一个典型的责任链模式实现:

责任链模式基本实现
java
1// 请求类
2public class Request {
3 private String type;
4 private String content;
5 private int priority;
6
7 public Request(String type, String content, int priority) {
8 this.type = type;
9 this.content = content;
10 this.priority = priority;
11 }
12
13 // getter方法
14 public String getType() { return type; }
15 public String getContent() { return content; }
16 public int getPriority() { return priority; }
17}
18
19// 处理者接口
20public abstract class Handler {
21 protected Handler successor;
22
23 public void setSuccessor(Handler successor) {
24 this.successor = successor;
25 }
26
27 public abstract void handleRequest(Request request);
28}
29
30// 具体处理者A
31public class ConcreteHandlerA extends Handler {
32 @Override
33 public void handleRequest(Request request) {
34 if ("TypeA".equals(request.getType())) {
35 System.out.println("处理者A处理请求:" + request.getContent());
36 } else if (successor != null) {
37 System.out.println("处理者A无法处理,转发给下一个处理者");
38 successor.handleRequest(request);
39 } else {
40 System.out.println("没有处理者能处理该请求");
41 }
42 }
43}
44
45// 具体处理者B
46public class ConcreteHandlerB extends Handler {
47 @Override
48 public void handleRequest(Request request) {
49 if ("TypeB".equals(request.getType())) {
50 System.out.println("处理者B处理请求:" + request.getContent());
51 } else if (successor != null) {
52 System.out.println("处理者B无法处理,转发给下一个处理者");
53 successor.handleRequest(request);
54 } else {
55 System.out.println("没有处理者能处理该请求");
56 }
57 }
58}
59
60// 具体处理者C
61public class ConcreteHandlerC extends Handler {
62 @Override
63 public void handleRequest(Request request) {
64 if (request.getPriority() > 10) {
65 System.out.println("处理者C处理高优先级请求:" + request.getContent());
66 } else if (successor != null) {
67 System.out.println("处理者C无法处理,转发给下一个处理者");
68 successor.handleRequest(request);
69 } else {
70 System.out.println("没有处理者能处理该请求");
71 }
72 }
73}
74
75// 客户端
76public class ChainOfResponsibilityDemo {
77 public static void main(String[] args) {
78 // 创建处理者
79 Handler handlerA = new ConcreteHandlerA();
80 Handler handlerB = new ConcreteHandlerB();
81 Handler handlerC = new ConcreteHandlerC();
82
83 // 构建责任链
84 handlerA.setSuccessor(handlerB);
85 handlerB.setSuccessor(handlerC);
86
87 // 创建请求
88 Request requestA = new Request("TypeA", "处理A类型请求", 5);
89 Request requestB = new Request("TypeB", "处理B类型请求", 8);
90 Request requestC = new Request("TypeC", "处理高优先级请求", 15);
91 Request requestD = new Request("TypeD", "无人能处理的请求", 2);
92
93 // 处理请求
94 handlerA.handleRequest(requestA); // 由处理者A处理
95 handlerA.handleRequest(requestB); // 由处理者B处理
96 handlerA.handleRequest(requestC); // 由处理者C处理
97 handlerA.handleRequest(requestD); // 无人处理
98 }
99}

责任链模式变体

纯的责任链模式中,一个请求只会被链中的一个处理者处理:

java
1// 纯责任链模式
2public abstract class PureHandler {
3 protected PureHandler successor;
4
5 public void setSuccessor(PureHandler successor) {
6 this.successor = successor;
7 }
8
9 public abstract boolean handleRequest(Request request);
10}
11
12public class ConcreteHandlerX extends PureHandler {
13 @Override
14 public boolean handleRequest(Request request) {
15 if ("TypeX".equals(request.getType())) {
16 System.out.println("处理者X处理请求:" + request.getContent());
17 return true; // 请求已处理,不再传递
18 } else if (successor != null) {
19 return successor.handleRequest(request);
20 }
21 return false; // 请求未被处理
22 }
23}
24
25// 使用示例
26public static void main(String[] args) {
27 PureHandler handlerX = new ConcreteHandlerX();
28 PureHandler handlerY = new ConcreteHandlerY();
29
30 handlerX.setSuccessor(handlerY);
31
32 boolean handled = handlerX.handleRequest(new Request("TypeX", "请求内容", 1));
33 System.out.println("请求是否被处理:" + handled);
34}

责任链模式应用实例

java
1// Web应用中的过滤器责任链
2public interface Filter {
3 void doFilter(Request request, Response response, FilterChain chain);
4}
5
6public class FilterChain {
7 private List<Filter> filters = new ArrayList<>();
8 private int index = 0;
9
10 public FilterChain addFilter(Filter filter) {
11 filters.add(filter);
12 return this;
13 }
14
15 public void doFilter(Request request, Response response) {
16 if (index < filters.size()) {
17 Filter filter = filters.get(index);
18 index++;
19 filter.doFilter(request, response, this);
20 }
21 }
22}
23
24// 安全过滤器
25public class SecurityFilter implements Filter {
26 @Override
27 public void doFilter(Request request, Response response, FilterChain chain) {
28 // 检查请求中的安全凭证
29 String token = request.getParameter("token");
30 if (token != null && validateToken(token)) {
31 System.out.println("SecurityFilter: 安全验证通过");
32 // 继续传递请求给下一个过滤器
33 chain.doFilter(request, response);
34 } else {
35 System.out.println("SecurityFilter: 安全验证失败");
36 response.setStatus(403); // Forbidden
37 }
38 }
39
40 private boolean validateToken(String token) {
41 return "valid_token".equals(token);
42 }
43}
44
45// 日志过滤器
46public class LoggingFilter implements Filter {
47 @Override
48 public void doFilter(Request request, Response response, FilterChain chain) {
49 System.out.println("LoggingFilter: 请求开始处理 - " + request.getUrl());
50
51 // 继续传递请求给下一个过滤器
52 chain.doFilter(request, response);
53
54 System.out.println("LoggingFilter: 请求处理完成 - 状态: " + response.getStatus());
55 }
56}
57
58// 缓存过滤器
59public class CacheFilter implements Filter {
60 private Map<String, String> cache = new HashMap<>();
61
62 @Override
63 public void doFilter(Request request, Response response, FilterChain chain) {
64 String url = request.getUrl();
65
66 if (cache.containsKey(url)) {
67 System.out.println("CacheFilter: 从缓存返回响应");
68 response.setContent(cache.get(url));
69 return; // 不再继续传递请求
70 }
71
72 System.out.println("CacheFilter: 未找到缓存,继续处理");
73 chain.doFilter(request, response);
74
75 // 缓存响应内容
76 if (response.getStatus() == 200) {
77 cache.put(url, response.getContent());
78 System.out.println("CacheFilter: 响应已缓存");
79 }
80 }
81}
82
83// 简化的请求和响应类
84public class Request {
85 private String url;
86 private Map<String, String> parameters = new HashMap<>();
87
88 public Request(String url) {
89 this.url = url;
90 }
91
92 public void addParameter(String name, String value) {
93 parameters.put(name, value);
94 }
95
96 public String getParameter(String name) {
97 return parameters.get(name);
98 }
99
100 public String getUrl() {
101 return url;
102 }
103}
104
105public class Response {
106 private int status = 200;
107 private String content = "";
108
109 public void setStatus(int status) {
110 this.status = status;
111 }
112
113 public int getStatus() {
114 return status;
115 }
116
117 public void setContent(String content) {
118 this.content = content;
119 }
120
121 public String getContent() {
122 return content;
123 }
124}
125
126// 使用示例
127public static void main(String[] args) {
128 FilterChain chain = new FilterChain();
129 chain.addFilter(new LoggingFilter())
130 .addFilter(new SecurityFilter())
131 .addFilter(new CacheFilter());
132
133 // 创建一个带有有效token的请求
134 Request request1 = new Request("http://example.com/api/data");
135 request1.addParameter("token", "valid_token");
136 Response response1 = new Response();
137
138 // 处理请求
139 chain.doFilter(request1, response1);
140
141 // 重置过滤器链,再次处理相同的URL(将使用缓存)
142 chain = new FilterChain();
143 chain.addFilter(new LoggingFilter())
144 .addFilter(new SecurityFilter())
145 .addFilter(new CacheFilter());
146
147 Request request2 = new Request("http://example.com/api/data");
148 request2.addParameter("token", "valid_token");
149 Response response2 = new Response();
150
151 chain.doFilter(request2, response2);
152}

责任链模式与其他模式比较

模式区别组合使用场景
责任链模式 vs 命令模式责任链关注的是谁来处理请求,命令模式关注的是如何封装请求可以在责任链中使用命令对象代表具体请求
责任链模式 vs 装饰器模式责任链处理者可以选择是否将请求传递给后续处理者,装饰器总是将请求传递给被装饰对象装饰器可以用于增强责任链的处理能力
责任链模式 vs 组合模式责任链通常是线性结构,组合模式是树形结构可以使用组合模式构建树形责任链

责任链模式实现要点

  1. 处理链的构建方式

    • 显式构建(手动设置后继者)
    • 自动构建(使用依赖注入或配置文件)
  2. 传递机制选择

    • 纯责任链:一个请求只由一个处理者处理
    • 多级处理链:一个请求可以被多个处理者处理
  3. 动态调整责任链

    java
    1// 动态调整责任链
    2public class DynamicChain {
    3 private List<Handler> handlers = new ArrayList<>();
    4 private Map<String, Integer> handlerPriority = new HashMap<>();
    5
    6 public void addHandler(String name, Handler handler, int priority) {
    7 handlers.add(handler);
    8 handlerPriority.put(name, priority);
    9
    10 // 按优先级排序
    11 handlers.sort((h1, h2) -> {
    12 String name1 = h1.getClass().getSimpleName();
    13 String name2 = h2.getClass().getSimpleName();
    14 return handlerPriority.get(name1) - handlerPriority.get(name2);
    15 });
    16
    17 // 重新构建链
    18 for (int i = 0; i < handlers.size() - 1; i++) {
    19 handlers.get(i).setSuccessor(handlers.get(i + 1));
    20 }
    21 }
    22
    23 public void removeHandler(String name) {
    24 handlers.removeIf(h -> h.getClass().getSimpleName().equals(name));
    25 handlerPriority.remove(name);
    26
    27 // 重新构建链
    28 for (int i = 0; i < handlers.size() - 1; i++) {
    29 handlers.get(i).setSuccessor(handlers.get(i + 1));
    30 }
    31 }
    32
    33 public void handleRequest(Request request) {
    34 if (!handlers.isEmpty()) {
    35 handlers.get(0).handleRequest(request);
    36 }
    37 }
    38}
  4. 异常处理

    java
    1// 处理链中的异常处理
    2public class HandlerWithExceptionHandling extends Handler {
    3 @Override
    4 public void handleRequest(Request request) {
    5 try {
    6 // 尝试处理请求
    7 doHandle(request);
    8 } catch (Exception e) {
    9 // 处理异常
    10 handleException(request, e);
    11 } finally {
    12 // 无论是否异常,都继续传递给下一个处理者
    13 if (successor != null) {
    14 successor.handleRequest(request);
    15 }
    16 }
    17 }
    18
    19 protected void doHandle(Request request) throws Exception {
    20 // 具体处理逻辑
    21 }
    22
    23 protected void handleException(Request request, Exception e) {
    24 System.out.println("处理请求时发生异常: " + e.getMessage());
    25 // 记录异常日志或执行其他异常处理操作
    26 }
    27}
  5. 返回处理结果

    java
    1// 带返回结果的处理链
    2public interface ResultHandler<T, R> {
    3 R handle(T request, HandlerChain<T, R> chain);
    4}
    5
    6public class HandlerChain<T, R> {
    7 private List<ResultHandler<T, R>> handlers = new ArrayList<>();
    8 private int index = 0;
    9 private R defaultResult;
    10
    11 public HandlerChain(R defaultResult) {
    12 this.defaultResult = defaultResult;
    13 }
    14
    15 public void addHandler(ResultHandler<T, R> handler) {
    16 handlers.add(handler);
    17 }
    18
    19 public R handle(T request) {
    20 if (index < handlers.size()) {
    21 ResultHandler<T, R> handler = handlers.get(index++);
    22 return handler.handle(request, this);
    23 }
    24 return defaultResult;
    25 }
    26}
责任链模式最佳实践
  • 明确每个处理者的职责范围和处理条件
  • 避免责任链过长,导致请求处理延迟
  • 为无法处理的请求提供默认处理机制
  • 考虑使用返回值表示处理状态,方便调试和追踪
  • 责任链适合流程处理,可以和状态模式结合实现复杂流程
  • 使用责任链代替复杂的if-else或switch语句
  • 结合命令模式可以实现可撤销的责任链

参与讨论