设计模式专栏(四):行为型设计模式(Behavioral Design Patterns)(关注“Beyond Code 程序员”订阅号查看更多文章)
模式介绍
行为型设计模式关注的是对象之间的通信与职责分配,它们用于定义对象之间的交互方式,确保系统中对象能够协作完成复杂的功能。 与创建型、结构型不同,行为型模式更侧重于算法的封装和对象职责的解耦,从而提高系统的灵活性与可维护性。
行为型模式可以帮助我们:
- 明确对象之间的职责划分
- 降低对象之间的耦合度
- 提高系统的可复用性和可扩展性
- 通过封装算法或流程,减少代码重复
主要包含十一种模式(常见经典行为型模式)
- 责任链模式(Chain of Responsibility Pattern)
- 命令模式(Command Pattern)
- 解释器模式(Interpreter Pattern)
- 迭代器模式(Iterator Pattern)
- 中介者模式(Mediator Pattern)
- 备忘录模式(Memento Pattern)
- 观察者模式(Observer Pattern)
- 状态模式(State Pattern)
- 策略模式(Strategy Pattern)
- 模板方法模式(Template Method Pattern)
- 访问者模式(Visitor Pattern)
⚠️ 提示:设计模式是一种编程思想,其实现方式并非唯一。本文示例代码仅作为参考,并不意味着设计模式必须按照示例中的方式实现。
1. 责任链模式(Chain of Responsibility Pattern)
模式解释
责任链模式核心思想是:
将请求沿着处理链传递,链上的每个对象都有机会处理该请求,直到有对象处理它为止。
适用场景:
- 多个对象可能处理同一个请求
- 希望避免请求发送者与接收者之间的耦合
- 处理逻辑需要动态组合或调整顺序
代码示例(Java,含测试代码)
// 抽象处理者
abstract class Handler {
protected Handler next;
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(int level);
}
// 具体处理者A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(int level) {
if (level == 1) {
System.out.println("HandlerA 处理了请求");
} else if (next != null) {
next.handleRequest(level);
}
}
}
// 具体处理者B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(int level) {
if (level == 2) {
System.out.println("HandlerB 处理了请求");
} else if (next != null) {
next.handleRequest(level);
}
}
}
// 测试代码
public class ChainDemo {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNext(handlerB);
handlerA.handleRequest(1); // HandlerA处理
handlerA.handleRequest(2); // HandlerB处理
handlerA.handleRequest(3); // 没有处理者
}
}
运行效果
HandlerA 处理了请求
HandlerB 处理了请求
总结
优点:
- 请求发送者与接收者解耦
- 增加或调整处理者顺序灵活
缺点:
- 请求可能一直传递而没有被处理
- 调试链路时不易追踪
2. 命令模式(Command Pattern)
模式解释
命令模式核心思想是:
将请求封装成对象,从而使你可用不同的请求、队列或者日志来参数化其他对象,并支持可撤销操作。
适用场景:
- 需要对操作进行记录、撤销、重做
- 需要将请求发送者与接收者解耦
代码示例(Java,含测试代码)
// 命令接口
interface Command {
void execute();
}
// 接收者
class Light {
public void on() {
System.out.println("灯打开了");
}
public void off() {
System.out.println("灯关闭了");
}
}
// 具体命令:打开灯
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
// 具体命令:关闭灯
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
// 调用者
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// 测试代码
public class CommandDemo {
public static void main(String[] args) {
Light light = new Light();
Command onCommand = new LightOnCommand(light);
Command offCommand = new LightOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(onCommand);
remote.pressButton();
remote.setCommand(offCommand);
remote.pressButton();
}
}
运行效果
灯打开了
灯关闭了
总结
优点:
- 解耦请求发送者与执行者
- 易于扩展新命令
- 支持撤销、重做、日志等功能
缺点:
- 增加了类的数量
3. 解释器模式(Interpreter Pattern)
模式解释
解释器模式核心思想是:
为某种语言定义文法,并建立一个解释器来解释该语言中的句子。
适用场景:
- 需要解释特定规则、表达式(如正则、脚本、公式)
- 语言文法规则相对稳定
代码示例(Java,含测试代码)
// 表达式接口
interface Expression {
boolean interpret(String context);
}
// 终结符表达式
class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data = data;
}
@Override
public boolean interpret(String context) {
return context.contains(data);
}
}
// 或表达式
class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
// 测试代码
public class InterpreterDemo {
public static void main(String[] args) {
Expression java = new TerminalExpression("Java");
Expression python = new TerminalExpression("Python");
Expression javaOrPython = new OrExpression(java, python);
System.out.println(javaOrPython.interpret("I love Java"));
System.out.println(javaOrPython.interpret("I love Go"));
}
}
运行效果
true
false
总结
优点:
- 易于实现简单文法的解析
- 扩展文法方便
缺点:
- 对于复杂文法会导致类爆炸
- 解释效率低
4. 迭代器模式(Iterator Pattern)
模式解释
迭代器模式核心思想是:
提供一种方法顺序访问聚合对象中的各个元素,而又不暴露其内部表示。
适用场景:
- 需要遍历集合但不想暴露集合内部结构
- 需要对遍历过程进行自定义
代码示例(Java,含测试代码)
import java.util.ArrayList;
import java.util.List;
// 自定义聚合类
class NameRepository {
private List<String> names = new ArrayList<>();
public void addName(String name) {
names.add(name);
}
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
return index < names.size();
}
@Override
public Object next() {
return hasNext() ? names.get(index++) : null;
}
}
}
// 迭代器接口
interface Iterator {
boolean hasNext();
Object next();
}
// 测试代码
public class IteratorDemo {
public static void main(String[] args) {
NameRepository repo = new NameRepository();
repo.addName("Jack");
repo.addName("Tom");
repo.addName("Lucy");
Iterator it = repo.getIterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行效果
Jack
Tom
Lucy
总结
优点:
- 遍历不暴露内部结构
- 可为不同集合结构提供统一访问接口
缺点:
- 对简单遍历可能显得多余
5. 中介者模式(Mediator Pattern)
模式解释
中介者模式核心思想是:
通过一个中介对象封装一系列对象之间的交互,使对象不需要显式地相互引用,从而降低耦合度。
适用场景:
- 系统中对象之间存在复杂引用关系
- 希望通过统一接口管理对象交互
代码示例(Java,含测试代码)
// 中介者接口
interface Mediator {
void sendMessage(String message, Colleague colleague);
}
// 具体中介者
class ConcreteMediator implements Mediator {
private ColleagueA colleagueA;
private ColleagueB colleagueB;
public void setColleagueA(ColleagueA colleagueA) {
this.colleagueA = colleagueA;
}
public void setColleagueB(ColleagueB colleagueB) {
this.colleagueB = colleagueB;
}
@Override
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleagueA) {
colleagueB.receive(message);
} else {
colleagueA.receive(message);
}
}
}
// 抽象同事类
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
}
// 具体同事A
class ColleagueA extends Colleague {
public ColleagueA(Mediator mediator) {
super(mediator);
}
public void send(String message) {
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println("ColleagueA 收到消息: " + message);
}
}
// 具体同事B
class ColleagueB extends Colleague {
public ColleagueB(Mediator mediator) {
super(mediator);
}
public void send(String message) {
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println("ColleagueB 收到消息: " + message);
}
}
// 测试代码
public class MediatorDemo {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
ColleagueA a = new ColleagueA(mediator);
ColleagueB b = new ColleagueB(mediator);
mediator.setColleagueA(a);
mediator.setColleagueB(b);
a.send("你好,B");
b.send("你好,A");
}
}
运行效果
ColleagueB 收到消息: 你好,B
ColleagueA 收到消息: 你好,A
总结
优点:
- 降低对象之间的耦合
- 便于维护对象交互逻辑
缺点:
- 中介者可能变成“上帝类”,逻辑过多导致复杂度高
6. 备忘录模式(Memento Pattern)
模式解释
备忘录模式核心思想是:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复到原先保存的状态。
适用场景:
- 需要保存对象的历史状态,以便撤销、恢复
- 需要防止外部直接访问对象的内部状态
代码示例(Java,含测试代码)
// 备忘录类
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 发起人
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void getStateFromMemento(Memento memento) {
state = memento.getState();
}
}
// 管理者
class CareTaker {
private java.util.List<Memento> mementoList = new java.util.ArrayList<>();
public void add(Memento state) {
mementoList.add(state);
}
public Memento get(int index) {
return mementoList.get(index);
}
}
// 测试代码
public class MementoDemo {
public static void main(String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("State #1");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #2");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #3");
originator.getStateFromMemento(careTaker.get(0));
System.out.println("恢复到: " + originator.getState());
}
}
运行效果
恢复到: State #1
总结
优点:
- 提供了状态的保存与恢复机制
- 封装了内部状态,保护数据安全
缺点:
- 可能消耗较多内存
7. 观察者模式(Observer Pattern)
模式解释
观察者模式核心思想是:
定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知并自动更新。
适用场景:
- 一个对象状态变化需要通知多个对象
- 解耦事件通知机制
代码示例(Java,含测试代码)
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update(String message);
}
// 主题
class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void notifyAllObservers(String message) {
for (Observer observer : observers) {
observer.update(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 + " 收到消息: " + message);
}
}
// 测试代码
public class ObserverDemo {
public static void main(String[] args) {
Subject subject = new Subject();
subject.attach(new ConcreteObserver("观察者A"));
subject.attach(new ConcreteObserver("观察者B"));
subject.notifyAllObservers("状态更新了");
}
}
运行效果
观察者A 收到消息: 状态更新了
观察者B 收到消息: 状态更新了
总结
优点:
- 建立了松耦合的通知机制
- 支持广播通信
缺点:
- 通知链可能比较长,影响性能
8. 状态模式(State Pattern)
模式解释
状态模式核心思想是:
允许对象在内部状态改变时改变它的行为,看起来好像修改了它的类。
适用场景:
- 对象的行为依赖于它的状态
- 状态切换逻辑复杂且多处出现
代码示例(Java,含测试代码)
// 状态接口
interface State {
void handle(Context context);
}
// 具体状态A
class ConcreteStateA implements State {
public void handle(Context context) {
System.out.println("当前状态:A -> 切换到 B");
context.setState(new ConcreteStateB());
}
}
// 具体状态B
class ConcreteStateB implements State {
public void handle(Context context) {
System.out.println("当前状态:B -> 切换到 A");
context.setState(new ConcreteStateA());
}
}
// 上下文
class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 测试代码
public class StateDemo {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request();
context.request();
}
}
运行效果
当前状态:A -> 切换到 B
当前状态:B -> 切换到 A
总结
优点:
- 将状态与行为分离,易于扩展新状态
- 避免冗长的 if/else 逻辑
缺点:
- 增加了类的数量
9. 策略模式(Strategy Pattern)
模式解释
策略模式核心思想是:
定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
适用场景:
- 需要在运行时选择不同的算法
- 避免多重条件语句
代码示例(Java,含测试代码)
// 策略接口
interface Strategy {
int doOperation(int num1, int num2);
}
// 具体策略:加法
class OperationAdd implements Strategy {
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
// 具体策略:减法
class OperationSubtract implements Strategy {
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
// 上下文
class ContextStrategy {
private Strategy strategy;
public ContextStrategy(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
// 测试代码
public class StrategyDemo {
public static void main(String[] args) {
ContextStrategy context = new ContextStrategy(new OperationAdd());
System.out.println("加法结果: " + context.executeStrategy(10, 5));
context = new ContextStrategy(new OperationSubtract());
System.out.println("减法结果: " + context.executeStrategy(10, 5));
}
}
运行效果
加法结果: 15
减法结果: 5
总结
优点:
- 提高算法的可扩展性和可维护性
- 避免使用大量条件语句
缺点:
- 客户端必须了解所有策略类
10. 模板方法模式(Template Method Pattern)
模式解释
模板方法模式核心思想是:
定义一个操作中算法的骨架,而将一些步骤延迟到子类中实现。
适用场景:
- 多个类中有相同算法结构,但部分步骤不同
- 希望在父类中定义流程,子类中扩展实现
代码示例(Java,含测试代码)
// 抽象类
abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
// 模板方法
public final void play() {
initialize();
startPlay();
endPlay();
}
}
// 具体类
class Football extends Game {
void initialize() { System.out.println("足球游戏初始化"); }
void startPlay() { System.out.println("足球游戏开始"); }
void endPlay() { System.out.println("足球游戏结束"); }
}
// 测试代码
public class TemplateDemo {
public static void main(String[] args) {
Game game = new Football();
game.play();
}
}
运行效果
足球游戏初始化
足球游戏开始
足球游戏结束
总结
优点:
- 封装了不可变的流程结构
- 子类只需实现个性化步骤
缺点:
- 父类对子类的约束较强
11. 访问者模式(Visitor Pattern)
模式解释
访问者模式核心思想是:
将作用于对象结构中的元素的操作分离出来,使得在不改变元素类的前提下增加新的操作。
适用场景:
- 数据结构稳定,但需要频繁新增操作
- 不希望在数据类中混入大量业务逻辑
代码示例(Java,含测试代码)
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素A
class ElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String featureA() {
return "特性A";
}
}
// 具体元素B
class ElementB implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String featureB() {
return "特性B";
}
}
// 访问者接口
interface Visitor {
void visit(ElementA elementA);
void visit(ElementB elementB);
}
// 具体访问者
class ConcreteVisitor implements Visitor {
public void visit(ElementA elementA) {
System.out.println("访问 ElementA: " + elementA.featureA());
}
public void visit(ElementB elementB) {
System.out.println("访问 ElementB: " + elementB.featureB());
}
}
// 测试代码
public class VisitorDemo {
public static void main(String[] args) {
Element[] elements = { new ElementA(), new ElementB() };
Visitor visitor = new ConcreteVisitor();
for (Element element : elements) {
element.accept(visitor);
}
}
}
运行效果
访问 ElementA: 特性A
访问 ElementB: 特性B
总结
优点:
- 新增操作方便
- 解耦数据结构与操作
缺点:
- 添加新元素类时需要修改所有访问者类
📌 下一篇: 设计模式专栏(五):设计模式在实际项目中的应用 —— 支付系统扩展与回调处理案例
扫码关注订阅号