文章目录
- [零 行为型模式概述](#零 行为型模式概述)
- [一 观察者模式](#一 观察者模式)
-
- [1.1 观察者模式的核心角色](#1.1 观察者模式的核心角色)
- [1.2 观察者模式的实现代码](#1.2 观察者模式的实现代码)
-
- [1.2.1 定义观察者接口](#1.2.1 定义观察者接口)
- [1.2.2 定义被观察者接口](#1.2.2 定义被观察者接口)
- [1.2.3 实现具体的被观察者](#1.2.3 实现具体的被观察者)
- 1.2.4实现具体的观察者
- [1.2.5 测试用例](#1.2.5 测试用例)
- [1.3 观察者模式的优缺点](#1.3 观察者模式的优缺点)
- [1.4 观察者模式的应用场景](#1.4 观察者模式的应用场景)
- [二 模版方法模式](#二 模版方法模式)
-
- [2.1 模版方法模式的核心思想](#2.1 模版方法模式的核心思想)
- [2.2 模版方法模式的核心角色](#2.2 模版方法模式的核心角色)
- [2.3 模版方法模式的实现代码](#2.3 模版方法模式的实现代码)
-
- [2.3.1 抽象类 `GameTemplate`](#2.3.1 抽象类
GameTemplate
) - [2.3.2 具体类 `FootballGame`](#2.3.2 具体类
FootballGame
) - [2.3.3 具体类 `ChessGame`](#2.3.3 具体类
ChessGame
) - [2.3.4 测试用例](#2.3.4 测试用例)
- [2.3.1 抽象类 `GameTemplate`](#2.3.1 抽象类
- [2.4 模版方法模式的优缺点](#2.4 模版方法模式的优缺点)
- [2.5 模版方法模式的应用场景](#2.5 模版方法模式的应用场景)
- [三 策略模式](#三 策略模式)
-
- [3.1 策略模式的核心思想](#3.1 策略模式的核心思想)
- [3.2 策略模式的核心角色](#3.2 策略模式的核心角色)
- [3.3 策略模式的实现](#3.3 策略模式的实现)
-
- [3.3.1 策略接口:`PaymentStrategy`](#3.3.1 策略接口:
PaymentStrategy
) - [3.3.2 具体策略类`CreditCardPayment`和`PayPalPayment`](#3.3.2 具体策略类
CreditCardPayment
和PayPalPayment
) - [3.3.3 上下文类:`ShoppingCart`](#3.3.3 上下文类:
ShoppingCart
) - [3.3.4 测试用例](#3.3.4 测试用例)
- [3.3.1 策略接口:`PaymentStrategy`](#3.3.1 策略接口:
- [3.4 策略模式的优缺点](#3.4 策略模式的优缺点)
- [3.5 策略模式的适用场景](#3.5 策略模式的适用场景)
- [3.6 策略模式的经典应用](#3.6 策略模式的经典应用)
- [3.7 和其他模式对比](#3.7 和其他模式对比)
- [四 责任链模式](#四 责任链模式)
-
- [4.1 责任链模式的核心思想](#4.1 责任链模式的核心思想)
- [4.2 责任链模式的核心角色](#4.2 责任链模式的核心角色)
- [4.3 责任链模式的实现代码](#4.3 责任链模式的实现代码)
-
- [4.3.1 数组方式](#4.3.1 数组方式)
- [4.3.2 链表方式](#4.3.2 链表方式)
- [4.4 责任链模式的优缺点](#4.4 责任链模式的优缺点)
- [4.5 责任链模式的应用场景](#4.5 责任链模式的应用场景)
- [五 状态模式](#五 状态模式)
-
- [5.1 状态模式的核心角色](#5.1 状态模式的核心角色)
- [5.2 状态模式的使用场景](#5.2 状态模式的使用场景)
- [5.3 状态模式的优缺点](#5.3 状态模式的优缺点)
- [5.4 状态模式的代码实现](#5.4 状态模式的代码实现)
-
- [5.4.1 定义状态接口](#5.4.1 定义状态接口)
- [5.4.2 具体状态类](#5.4.2 具体状态类)
- [5.4.3 上下文类](#5.4.3 上下文类)
- [5.4.4 使用示例](#5.4.4 使用示例)
- [5.5 状态模式的状态机](#5.5 状态模式的状态机)
-
- [5.5.1 状态机分支判断法](#5.5.1 状态机分支判断法)
- [5.5.2 查表法](#5.5.2 查表法)
- [5.5.3 状态模式](#5.5.3 状态模式)
- [六 迭代器模式](#六 迭代器模式)
-
- [6.1 迭代器模式的核心角色](#6.1 迭代器模式的核心角色)
- [6.2 迭代器模式的实现代码](#6.2 迭代器模式的实现代码)
- [6.3 迭代器模式的优点](#6.3 迭代器模式的优点)
- [6.4 迭代器模式的适用场景](#6.4 迭代器模式的适用场景)
- [6.5 迭代器模式的Java 内置支持](#6.5 迭代器模式的Java 内置支持)
- [七 访问者模式](#七 访问者模式)
-
- [7.1 访问者模式的核心思想](#7.1 访问者模式的核心思想)
- [7.2 访问者模式的核心角色](#7.2 访问者模式的核心角色)
- [7.3 访问者模式的代码实现](#7.3 访问者模式的代码实现)
- [7.4 访问者模式的使用场景](#7.4 访问者模式的使用场景)
- [7.5 访问者模式的优缺点](#7.5 访问者模式的优缺点)
- [八 备忘录模式](#八 备忘录模式)
-
- [8.1 备忘录模式的核心思想](#8.1 备忘录模式的核心思想)
- [8.2 备忘录模式的核心角色](#8.2 备忘录模式的核心角色)
- [8.3 备忘录模式的代码实现](#8.3 备忘录模式的代码实现)
- [8.4 备忘录模式的优缺点](#8.4 备忘录模式的优缺点)
- [8.5 备忘录模式的应用场景](#8.5 备忘录模式的应用场景)
- 九命令模式
-
- [9.1 命令模式的核心角色](#9.1 命令模式的核心角色)
- [9.2 命令模式的代码实现](#9.2 命令模式的代码实现)
- [9.3 命令模式的优点](#9.3 命令模式的优点)
- [9.4 命令模式的适用场景](#9.4 命令模式的适用场景)
- [十 解释器模式](#十 解释器模式)
-
- [10.1 解释器模式的核心角色](#10.1 解释器模式的核心角色)
- [10.2 解释器模式的代码实现](#10.2 解释器模式的代码实现)
- [10.3 解释器模式的优缺点](#10.3 解释器模式的优缺点)
- [10.4 解释器模式的适用场景](#10.4 解释器模式的适用场景)
- [10.5 解释器模式的实际应用](#10.5 解释器模式的实际应用)
- [十一 中介模式](#十一 中介模式)
-
- [11.1 中介者模式的核心角色](#11.1 中介者模式的核心角色)
- [11.2 终结者模式的代码实现](#11.2 终结者模式的代码实现)
- [11.3 中介者模式的应用场景](#11.3 中介者模式的应用场景)
- [11.4 中介者模式的优缺点](#11.4 中介者模式的优缺点)
- [11.5 中介者模式的适用性](#11.5 中介者模式的适用性)

零 行为型模式概述
- 行为型模式关注的是对象之间的通信,也就是描述多个类或者对象之间,通过协作共同完成一个任务。主要涉及对象和算法之间的职责分配。
- 行为型模式分为两类:
- 类行为模式:通过继承机制来在类间分派行为,主要通过多态来分类父类和子类的职责。
- 对象行为模式:通过组合或聚合,在对象间分配行为。通过对象关联等方式来分类类的职责。
一 观察者模式
- 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知并更新。在这个场景中,发生改变的对象称为观察目标,被通知的对象称为观察者。一个观察目标可以有过个观察者,而这些观察者之间没有联系,可以根据需要增减。
- 观察者模式又称为发布/订阅(Publish/Subscribe)模式,在对象之间定义了一对多的依赖。当一个对象改变状态,依赖它的对象会收到通知并自动更新。
1.1 观察者模式的核心角色
Subject
(被观察者/主题):维护观察者列表,并提供注册、移除和通知观察者的方法。Observer
(观察者):定义一个更新接口,用于在被观察者状态变化时接收通知。ConcreteSubject
(具体被观察者):实现主题接口,保存状态信息,在状态变化时通知所有观察者。ConcreteObserver
(具体观察者):实现更新方法,响应被观察者的状态变化。
1.2 观察者模式的实现代码
1.2.1 定义观察者接口
java
public interface Observer {
void update(String message);
}
1.2.2 定义被观察者接口
java
import java.util.List;
import java.util.ArrayList;
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
1.2.3 实现具体的被观察者
java
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
// 模拟状态变化并通知观察者
public void someBusinessLogic() {
System.out.println("Subject: 发生了某些业务逻辑变化");
notifyObservers("状态已更新!");
}
}
1.2.4实现具体的观察者
java
public 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);
}
}
1.2.5 测试用例
java
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("观察者1");
Observer observer2 = new ConcreteObserver("观察者2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.someBusinessLogic();
subject.removeObserver(observer1);
subject.someBusinessLogic();
}
}
-
执行结果
bashSubject: 发生了某些业务逻辑变化 观察者1 收到通知: 状态已更新! 观察者2 收到通知: 状态已更新! Subject: 发生了某些业务逻辑变化 观察者2 收到通知: 状态已更新!
1.3 观察者模式的优缺点
优点
- 解耦:被观察者和观察者之间是松耦合的,它们可以属于不同的模块或层级。
- 可扩展性:新增观察者无需修改被观察者代码,符合开闭原则。
- 支持广播通信:被观察者状态变化后会自动通知所有观察者。
缺点
- 性能问题(观察者过多):当观察者数量较多或更新逻辑复杂时,通知过程可能造成性能瓶颈。特别是在同步调用场景下,可能阻塞主线程。
- 内存泄漏风险:如果观察者未及时注销(unregister),可能导致内存泄漏。尤其在长期运行的对象作为观察者时,需手动管理生命周期。
- 顺序和依赖不确定:观察者的执行顺序通常不明确,若业务逻辑对顺序敏感,可能导致不可预期行为。各观察者之间不应有强依赖关系,否则难以维护。
- 复杂度上升:随着观察者数量和逻辑增多,系统复杂度提升,调试和维护难度增加。可能出现"链式通知"或"循环依赖",导致系统不稳定。
- 异常传播风险:某个观察者的 update() 方法抛出异常,可能中断后续观察者的执行流程。需要额外处理异常隔离机制。
- 过度设计:对于简单的一对一通信场景,使用观察者模式可能显得冗余,增加不必要的抽象层级。
1.4 观察者模式的应用场景
- 事件监听机制(如 GUI 中的按钮点击)
- MVC 架构中模型与视图之间的同步
- 订阅-发布系统
- 数据变更通知
二 模版方法模式
- 模板方法模式(Template Method Pattern)是行为型设计模式之一,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。
2.1 模版方法模式的核心思想
- 定义一个抽象类(Abstract Class):其中包含一个模板方法和若干基本方法。
- 模板方法(Template Method):定义算法的骨架,通常是一个具体方法,调用多个基本方法。
- 基本方法(Primitive Methods):可以是抽象方法(由子类实现),也可以是钩子方法(Hook Method),提供默认实现,子类可选择性覆盖。
2.2 模版方法模式的核心角色
角色 | 职责 |
---|---|
AbstractClass |
定义抽象类,声明模板方法和基本方法(包括抽象方法和钩子方法) |
ConcreteClass |
实现抽象类中的抽象方法,可以覆盖钩子方法 |
2.3 模版方法模式的实现代码
2.3.1 抽象类 GameTemplate
java
public abstract class GameTemplate {
// 模板方法,定义了算法骨架
public final void play() {
initialize();
startGame();
endGame();
}
// 基本方法 - 初始化
protected abstract void initialize();
// 基本方法 - 开始游戏
protected abstract void startGame();
// 钩子方法 - 可选实现
protected void endGame() {
System.out.println("Game ended.");
}
}
2.3.2 具体类 FootballGame
java
public class FootballGame extends GameTemplate {
@Override
protected void initialize() {
System.out.println("Football game initialized.");
}
@Override
protected void startGame() {
System.out.println("Football match started.");
}
}
2.3.3 具体类 ChessGame
java
public class ChessGame extends GameTemplate {
@Override
protected void initialize() {
System.out.println("Chess game initialized.");
}
@Override
protected void startGame() {
System.out.println("Chess match started.");
}
@Override
protected void endGame() {
System.out.println("Chess game ended with checkmate.");
}
}
2.3.4 测试用例
java
public class Client {
public static void main(String[] args) {
GameTemplate football = new FootballGame();
football.play();
GameTemplate chess = new ChessGame();
chess.play();
}
}
2.4 模版方法模式的优缺点
优点:
- 封装不变部分,扩展可变部分:算法骨架固定,子类只需实现变化的部分。
- 提高代码复用性:公共逻辑在父类中实现,避免重复代码。
- 符合开闭原则:新增子类不影响已有逻辑。
缺点:
- 增加子类复杂度:每个不同实现都需要一个子类。
- 违反里氏替换原则(LSP)风险:如果钩子方法被错误重写,可能影响整体流程。
2.5 模版方法模式的应用场景
JdbcTemplate
中的execute()
方法即为模板方法。Servlet
中的doGet()
/doPost()
是钩子方法。Spring
框架中大量使用模板方法模式,如JmsTemplate
,RestTemplate
等。
三 策略模式
- 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用它的客户端。
3.1 策略模式的核心思想
- 将算法或行为封装为独立的类。客户端通过统一接口调用不同的实现,从而实现算法的动态切换。
3.2 策略模式的核心角色
角色 | 职责 |
---|---|
Strategy 接口 |
定义算法公共操作,是策略的抽象 |
ConcreteStrategy 类 |
实现具体算法 |
Context 类 |
持有一个策略对象的引用,最终调用策略 |
3.3 策略模式的实现
3.3.1 策略接口:PaymentStrategy
java
public interface PaymentStrategy {
void pay(int amount);
}
3.3.2 具体策略类CreditCardPayment
和PayPalPayment
java
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card.");
}
}
java
public class PayPalPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal.");
}
}
3.3.3 上下文类:ShoppingCart
java
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int totalAmount) {
if (paymentStrategy != null) {
paymentStrategy.pay(totalAmount);
} else {
System.out.println("No payment strategy set.");
}
}
}
3.3.4 测试用例
java
public class Client {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 设置支付策略为信用卡支付
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // 输出: Paid 100 via Credit Card.
// 切换为PayPal支付
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(200); // 输出: Paid 200 via PayPal.
}
}
3.4 策略模式的优缺点
优点
- 解耦:客户端与具体算法解耦。
- 扩展性强:新增策略只需添加新类,符合开闭原则。
- 易于替换:运行时可动态切换策略。
缺点
- 策略类数量多时,可能增加系统复杂度。
- 所有策略类都需要对外暴露。
3.5 策略模式的适用场景
- 多种相似算法或行为需要在运行时动态切换。
- 用于替代多重条件判断语句。
- 需要隐藏算法实现细节的场合。
3.6 策略模式的经典应用
- 数据验证:Spring框架提供Validator接口,允许开发者定义验证规则。通过实现不同的验证策略(如电子邮件验证,值范围验证等),可以在不同场景中使用不同的验证器,提高代码的复用性和灵活性。
- 缓存管理:Spring Cache提供Cache接口,允许开发者定义缓存策略,可以实现不同的缓存策略(如LRU缓存,FIFO缓存),并在服务方法中使用
@Cacheable
注解来指定缓存策略,从而在不修改业务逻辑的情况下优化系统性能。 - 事务处理:Spring容器提供事务管理服务,允许开发者定义不同的事务策略,并在服务方法中使用
@Transactional
注解来指定事务策略,方便开发者在不同业务场景下灵活选择处理事务的方式。 - 依赖注入:Spring提供DI规范,允许开发者使用
@Autowird
注解将依赖注入类中。通过定义不同的依赖注入策略,实现在不修改代码的情况下灵活地管理依赖关系。 - 多种算法选择:策略模式还常用于动态选择多种算法的场景。如,在支付系统中,不同的支付方式可以对应不同的结算方法;在物流系统中,不同的车型可能对应不同的物流规则。通过定义抽象策略和具体策略类,可以在运行时根据需求选择合适的算法进行处理。
- 场景模式:在场景模拟中,如游戏开发、仿真实验等。根据不同的条件选择不同的算法或行为。策略模式可以将这些算法或行为封装成独立的策略类,并在运行时根据条件动态选择使用策略类。
3.7 和其他模式对比
模式 | 区别 |
---|---|
状态模式 | 策略模式是无状态的,而状态模式内部维护状态变化 |
模板方法 | 模板方法是通过继承固定流程,策略是通过组合方式改变行为 |
四 责任链模式
- 责任链模式(Chain of Responsibility Pattern)是行为型设计模式之一,它允许将请求沿着处理者对象链进行传递,并让每个处理者决定是否处理该请求。这种方式实现了请求的发送者和接收者之间的解耦。
- 责任链模式适用于请求的处理流程不确定或需要动态配置的场景,能够有效实现请求与处理者的解耦,提升系统的灵活性和可维护性。
4.1 责任链模式的核心思想
- 解耦请求发送者和处理者:发送者无需知道具体处理者,只需要将请求发送到链上的第一个节点。
- 动态调整处理逻辑:通过改变链的结构,可以灵活地增加、删除或修改请求的处理逻辑。
4.2 责任链模式的核心角色
- Handler(抽象处理者):定义一个处理请求的接口,通常包含一个指向下一个处理者的引用。
- ConcreteHandler(具体处理者):实现具体的请求处理逻辑,如果自己无法处理,则转发给下一个处理者。
- Client(客户端):创建请求并将其提交给链上的第一个处理者。
4.3 责任链模式的实现代码
4.3.1 数组方式
java
// 责任链模式 基于数组的方式实现
public interface Handler {
boolean handle();
}
public class HandlerA implements Handler {
@Override
public boolean handle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理A......");
return false;
}
}
public class HandlerB implements Handler {
@Override
public boolean handle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理B......");
return false;
}
}
public class HandlerC implements Handler {
@Override
public boolean handle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理C......");
return false;
}
}
/**
* 责任链
*/
public class HandlerChain {
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
handlers.add(handler);
}
public void handle() {
for (Handler handler : handlers) {
boolean handled = handler.handle() ;
if (handled) {
break;
}
}
}
}
public class Client {
public static void main(String[] args) {
HandlerChain handlerChain = new HandlerChain();
handlerChain.addHandler(new HandlerA());
handlerChain.addHandler(new HandlerB());
handlerChain.handle();
}
}
4.3.2 链表方式
java
//责任链中处理器的父类
public abstract class Handler {
//持有下一个处理器的引用
protected Handler nextHandler=null;
// 持有下一个处理器的引用
public void setSuccessor(Handler successor) {
this.nextHandler=successor;
}
// 定义抽象处理方法
protected abstract boolean doHandle();
// 定义一个处理业务的方法
public final void handle() {
//让具体的处理器处理
boolean isHandle = doHandle();
// 如果没有处理,则将请求传递给下一个处理
if(!isHandle && nextHandler!=null) {
nextHandler.handle();
}
}
}
public class HandlerA extends Handler{
@Override
protected boolean doHandle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理A......");
return false;
}
}
public class HandlerB extends Handler{
@Override
protected boolean doHandle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理B......");
return false;
}
}
public class HandlerC extends Handler{
@Override
protected boolean doHandle() {
boolean handle = false;
//结合自身处理逻辑判断是否需要处理
System.out.println("处理C......");
return false;
}
}
/**
* 责任链
*/
public class HandlerChain {
private Handler head = null;
private Handler tail = null;
public void addHandler(Handler handler){
handler.setSuccessor(null);
if(head == null){
head = handler;
tail = handler;
}else{
tail.setSuccessor(handler);
tail = handler;
}
}
/**
* 执行链路执行
*/
public void handle(){
if(head != null){
head.handle();
}
}
}
public class Client {
public static void main(String[] args) {
HandlerChain handlerChain = new HandlerChain();
handlerChain.addHandler(new HandlerA());
handlerChain.addHandler(new HandlerB());
handlerChain.handle();
}
}
4.4 责任链模式的优缺点
优点
- 降低耦合度:请求的发送者不需要知道具体的处理者,只需将请求发送到链上即可。
- 增强系统的可扩展性:可以灵活地添加、修改或移除处理者。
- 符合开闭原则:增加新的处理者时,无需修改现有代码。
缺点
- 性能问题:如果链过长或处理逻辑复杂,可能会影响性能。
- 请求可能未被处理:如果链中没有合适的处理者,请求可能会被丢弃而不做任何处理。
4.5 责任链模式的应用场景
- 审批流程:例如请假申请需要多级审批,每一级根据权限判断是否处理。
- 过滤器链:如 Web 请求经过多个拦截器进行日志记录、身份验证等。
- 异常处理机制:不同层级的异常处理器按优先级依次尝试处理异常。
五 状态模式
- 状态模式(State Pattern)是行为型设计模式之一,它允许对象在其内部状态改变时改变其行为。该模式将状态相关的行为封装到独立的状态类中,使得对象的状态变化更加清晰和可维护。
- 状态模式允许一个对象基于其内部状态来改变行为,看起来像是修改了自身的类。
5.1 状态模式的核心角色
- Context(上下文) :拥有状态的对象,维护一个对
State
接口的引用,通过委托给当前状态对象来处理请求。 - State(状态接口):定义状态相关的公共行为,通常是一个接口或抽象类。
- ConcreteState(具体状态类):实现与特定状态相关的行为。
5.2 状态模式的使用场景
- 对象的行为依赖于其状态,并且需要在运行时根据状态动态调整行为。
- 避免大量条件判断语句(如
if-else
或switch-case
)导致代码难以维护。 - 状态转换逻辑复杂,需要清晰地分离各个状态行为。
5.3 状态模式的优缺点
优点
- 消除冗长的条件判断:将状态逻辑分散到各个状态类中,提高代码可读性和可维护性。
- 开闭原则:增加新的状态只需扩展,不需修改已有代码。
- 职责分离:每个状态类只处理自身逻辑,符合单一职责原则。
缺点
- 如果状态较少或逻辑简单,引入状态模式可能导致类数量增多、结构复杂。
- 状态转换逻辑如果过于复杂,可能需要额外管理状态之间的关系。
5.4 状态模式的代码实现
5.4.1 定义状态接口
java
public interface State {
void handle(Context context);
}
5.4.2 具体状态类
java
public class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态为 A,执行操作...");
context.setState(new ConcreteStateB());
}
}
public class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态为 B,执行操作...");
context.setState(new ConcreteStateA());
}
}
5.4.3 上下文类
java
public class Context {
private State state;
public Context(State initialState) {
this.state = initialState;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
5.4.4 使用示例
java
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request(); // 输出 "当前状态为 A,执行操作...",切换为 B
context.request(); // 输出 "当前状态为 B,执行操作...",切换为 A
}
}
5.5 状态模式的状态机
- 状态模式中的状态机分为3种:分支判断、查表法和状态模式。通过《超级马里奥》这款游戏进行介绍,马里奥可以变身成为多种状态:小马里奥(Small Mario)、超级马里奥(Super Mario)、火焰马里奥(Fire Mario)、斗篷马里奥(Cape Mario)。在不同的情节中各个形态会互相转换,并相应的增减积分,示意图如下:
符号 | 含义 |
---|---|
E1 | 吃了蘑菇 |
E2 | 获得斗篷 |
E3 | 获得火焰 |
E4 | 碰到怪物 |
5.5.1 状态机分支判断法
java
// 状态枚举类
public enum State {
SMALL(0),
SUPER(1),
FIRE(2),
CAPE(3);
private int value;
State(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
// 马里奥的状态机
public class MarioStateMachine {
private int score; // 分数
private State currentState;// 当前状态
public MarioStateMachine() {
this.score = 100;
this.currentState = State.SMALL;
}
/**
* 获得蘑菇
*/
public void obtainMushRoom() {
if (currentState == State.SMALL) {
currentState = State.SUPER;
score += 100;
}
}
public void lossMushRoom() {
if (currentState == State.SUPER) {
currentState = State.SMALL;
score -= 100;
}
}
/**
* 获得斗篷
*/
public void obtainCape() {
if (currentState == State.SMALL || currentState == State.SUPER) {
currentState = State.CAPE;
score += 200;
}
}
public void lossCape() {
if (currentState == State.CAPE) {
currentState = State.SMALL;
score -= 200;
}
}
/**
* 获得火焰
*/
public void obtainFire() {
if (currentState == State.SMALL || currentState == State.SUPER) {
currentState = State.FIRE;
score += 300;
}
}
public void lossFire() {
if (currentState == State.FIRE) {
currentState = State.SMALL;
score -= 300;
}
}
/**
* 遇到怪物
*/
public void meetMonster() {
if (currentState == State.FIRE) {
currentState = State.SMALL;
score -= 100;
} else if (currentState == State.CAPE) {
currentState = State.SMALL;
score -= 200;
} else if (currentState == State.SUPER) {
currentState = State.SMALL;
}
}
public int getScore() {
return score;
}
public State getCurrentState() {
return currentState;
}
}
//测试用例
public class AppStart {
public static void main(String[] args) {
MarioStateMachine marioStateMachine = new MarioStateMachine();
marioStateMachine.obtainMushRoom();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
marioStateMachine.obtainCape();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
marioStateMachine.meetMonster();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
}
}
5.5.2 查表法

符号 | 含义 |
---|---|
E1 | 吃了蘑菇 |
E2 | 获得斗篷 |
E3 | 获得火焰 |
E4 | 碰到怪物 |
java
//马里奥的角色状态
public enum State {
SMALL(0),
SUPER(1),
FIRE(2),
CAPE(3);
private int value;
State(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
// 事件枚举
public enum Event {
OBTAIN_MUSHROOM(0),
OBTAIN_CAPE(1),
OBTAIN_FIRE(2),
MEET_MONSTER(3);
private int value;
Event(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
}
// 状态机
public class MarioStateMachine {
private int score;
private State currentState;
public MarioStateMachine() {
this.score = 100;
this.currentState = State.SMALL;
}
//定义状态和积分的二维数组
private static final State[][] transitionTable = {
{State.SUPER, State.CAPE, State.FIRE, State.SMALL},
{State.SUPER, State.CAPE, State.FIRE, State.SMALL},
{State.CAPE, State.CAPE, State.CAPE, State.SMALL},
{State.FIRE, State.FIRE, State.FIRE, State.SMALL},
};
private static final int[][] actionTable = {
{100, 200, 300, 0},
{0, 200, 300, -100},
{0, 0, 0, -200},
{0, 0, 0, -300},
};
public void obtainMushRoom(){
executeEvent(Event.OBTAIN_MUSHROOM);
}
public void obtainCape(){
executeEvent(Event.OBTAIN_CAPE);
}
public void obtainFire(){
executeEvent(Event.OBTAIN_FIRE);
}
public void meetMonster(){
executeEvent(Event.MEET_MONSTER);
}
public int getScore() {
return score;
}
public State getCurrentState() {
return currentState;
}
public void executeEvent(Event event) {
int stateValue = currentState.getValue();
int eventValue = event.getValue();
this.currentState = transitionTable[stateValue][eventValue];
this.score += actionTable[stateValue][eventValue];
}
}
//测试用例
public class AppStart {
public static void main(String[] args) {
MarioStateMachine marioStateMachine = new MarioStateMachine();
marioStateMachine.obtainMushRoom();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
marioStateMachine.obtainCape();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
marioStateMachine.meetMonster();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());
}
}
5.5.3 状态模式
java
//枚举类
public enum State {
SMALL(0),
SUPER(1),
FIRE(2),
CAPE(3);
private int value;
State(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
//状态模式 公共接口
public interface IMario {
State getName();
void obtainMushRoom(MarioStateMachine machine);
void obtainCape(MarioStateMachine machine);
void obtainFire(MarioStateMachine machine);
void meetMonster(MarioStateMachine machine);
}
// 状态机
public class MarioStateMachine {
private int score;
private IMario mario;
public MarioStateMachine() {
this.score = 100;
this.mario = SmallMario.getInstance();
}
public void obtainMushRoom(){
mario.obtainMushRoom(this);
}
public void obtainCape(){
mario.obtainCape(this);
}
public void obtainFire(){
mario.obtainFire(this);
}
public void meetMonster(){
mario.meetMonster(this);
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public IMario getMario() {
return mario;
}
public void setMario(IMario mario) {
this.mario = mario;
}
}
//超级马里奥
public class SuperMario implements IMario{
private static final SuperMario instance = new SuperMario();
private SuperMario(){}
public static SuperMario getInstance(){
return instance;
}
@Override
public State getName() {
return State.SUPER;
}
@Override
public void obtainMushRoom(MarioStateMachine machine) {
machine.setMario(SuperMario.getInstance());
machine.setScore(machine.getScore() + 100);
}
@Override
public void obtainCape(MarioStateMachine machine) {
machine.setMario(CapeMario.getInstance());
machine.setScore(machine.getScore() + 200);
}
@Override
public void obtainFire(MarioStateMachine machine) {
machine.setMario(FireMario.getInstance());
machine.setScore(machine.getScore() + 300);
}
@Override
public void meetMonster(MarioStateMachine machine) {
machine.setMario(SmallMario.getInstance());
machine.setScore(machine.getScore() - 100);
}
}
//小马里奥
public class SmallMario implements IMario{
private static final SmallMario instance = new SmallMario();
private SmallMario(){}
public static SmallMario getInstance(){
return instance;
}
@Override
public State getName() {
return State.SMALL;
}
@Override
public void obtainMushRoom(MarioStateMachine machine) {
}
@Override
public void obtainCape(MarioStateMachine machine) {
machine.setMario(CapeMario.getInstance());
machine.setScore(machine.getScore() + 200);
}
@Override
public void obtainFire(MarioStateMachine machine) {
machine.setMario(SmallMario.getInstance());
machine.setScore(machine.getScore() + 300);
}
@Override
public void meetMonster(MarioStateMachine machine) {
}
}
//火焰马里奥
public class FireMario implements IMario{
private static final FireMario instance = new FireMario();
private FireMario(){}
public static FireMario getInstance(){
return instance;
}
@Override
public State getName() {
return State.FIRE;
}
@Override
public void obtainMushRoom(MarioStateMachine machine) {
}
@Override
public void obtainCape(MarioStateMachine machine) {
machine.setMario(CapeMario.getInstance());
machine.setScore(machine.getScore() + 200);
}
@Override
public void obtainFire(MarioStateMachine machine) {
machine.setMario(FireMario.getInstance());
machine.setScore(machine.getScore() + 300);
}
@Override
public void meetMonster(MarioStateMachine machine) {
machine.setMario(SmallMario.getInstance());
machine.setScore(machine.getScore() - 300);
}
}
// 帽子马里奥
public class CapeMario implements IMario{
private static final CapeMario instance = new CapeMario();
private CapeMario(){}
public static CapeMario getInstance(){
return instance;
}
@Override
public State getName() {
return State.CAPE;
}
@Override
public void obtainMushRoom(MarioStateMachine machine) {
}
@Override
public void obtainCape(MarioStateMachine machine) {
}
@Override
public void obtainFire(MarioStateMachine machine) {
}
@Override
public void meetMonster(MarioStateMachine machine) {
machine.setMario(SmallMario.getInstance());
machine.setScore(machine.getScore() - 200);
}
}
//测试用例
public class AppStart {
public static void main(String[] args) {
MarioStateMachine marioStateMachine = new MarioStateMachine();
marioStateMachine.obtainMushRoom();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());
marioStateMachine.obtainCape();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());
marioStateMachine.meetMonster();
System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());
}
}
bash
当前分数:100 当前状态:SMALL
当前分数:300 当前状态:CAPE
当前分数:100 当前状态:SMALL
六 迭代器模式
- 场景:访问聚合对象中的各种元素的时候,如链表的遍历,一般都是将遍历的方法放到链表类中。但如果需要修改遍历方法,就需要修改链表类的代码,违背开闭原则。迭代器模式就是在客户访问和聚合类之间插入一个迭代器,将聚合对象和遍历方法解耦,并且对外隐藏其实现细节。
- 迭代器模式(Iterator Pattern)是行为型设计模式之一,用于提供一种统一的方式来访问集合中的元素,同时隐藏集合的内部结构。
6.1 迭代器模式的核心角色
- Iterator(迭代器接口) :定义遍历集合的基本操作,如
hasNext()
、next()
等。 - ConcreteIterator(具体迭代器):实现迭代器接口,并跟踪遍历过程中的当前位置。
- Aggregate(集合接口) :定义创建相应迭代器对象的方法,如
iterator()
。 - ConcreteAggregate(具体集合):实现创建具体迭代器对象的方法,返回一个与该集合相关的迭代器。
6.2 迭代器模式的实现代码
java
// 迭代器接口
interface Iterator<T> {
boolean hasNext();
T next();
}
// 具体迭代器
class ListIterator<T> implements Iterator<T> {
private List<T> items;
private int position = 0;
public ListIterator(List<T> items) {
this.items = items;
}
@Override
public boolean hasNext() {
return position < items.size();
}
@Override
public T next() {
if (hasNext()) {
return items.get(position++);
}
return null;
}
}
// 集合接口
interface Aggregate<T> {
Iterator<T> iterator();
}
// 具体集合
class ListAggregate<T> implements Aggregate<T> {
private List<T> items = new ArrayList<>();
public void add(T item) {
items.add(item);
}
@Override
public Iterator<T> iterator() {
return new ListIterator<>(items);
}
}
- 测试用例
java
public class Main {
public static void main(String[] args) {
ListAggregate<String> aggregate = new ListAggregate<>();
aggregate.add("A");
aggregate.add("B");
aggregate.add("C");
Iterator<String> iterator = aggregate.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next()); # A B C
}
}
}
6.3 迭代器模式的优点
- 解耦:分离集合对象的使用和内部结构的遍历逻辑。
- 扩展性强:可以为不同集合类型定义不同的迭代器。
- 统一接口:客户端无需知道集合的具体类型即可遍历元素。
6.4 迭代器模式的适用场景
- 当需要统一访问多种集合类型时。
- 需要隐藏集合内部结构时。
- 支持多种遍历方式(如倒序、过滤等)。
6.5 迭代器模式的Java 内置支持
Java 标准库已内置迭代器模式:
java.util.Iterator
是标准的迭代器接口。java.lang.Iterable
接口定义了iterator()
方法,许多集合类(如List
、Set
)都实现了它。
java
// 增强型 for 循环底层就依赖于 `Iterable` 和 `Iterator`。
List<String> list = Arrays.asList("X", "Y", "Z");
for (String s : list) {
System.out.println(s);
}
七 访问者模式
- 访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你将作用于某些对象结构中的各元素的操作分离出来,集中到一个访问者对象中,从而使得不改变对象结构的情况下增加新的操作。【解耦数据结构和操作】
- 访问者模式适用于对象结构稳定、操作多变的场景,通过将操作从对象结构中抽离,实现了高内聚低耦合的设计理念。但在实际使用中需权衡是否值得牺牲封装性来换取灵活性。
7.1 访问者模式的核心思想
- 将数据结构与数据操作分离。
- 在不修改元素类的前提下,为元素添加新的操作。
7.2 访问者模式的核心角色
角色 | 描述 |
---|---|
Visitor |
抽象访问者接口,定义对各个元素的访问操作。 |
ConcreteVisitor |
具体访问者实现,实现针对不同元素的具体操作。 |
Element |
抽象元素接口,定义接受访问者的方法 accept(Visitor visitor) 。 |
ConcreteElement |
具体元素实现,实现 accept 方法,并调用访问者的处理方法。 |
ObjectStructure |
对象结构,包含一组元素对象,提供让访问者访问的接口。 |
7.3 访问者模式的代码实现
java
// Visitor 接口
interface Visitor {
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
}
// 具体访问者
class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA elementA) {
System.out.println("访问者处理元素 A:" + elementA.operation());
}
@Override
public void visit(ConcreteElementB elementB) {
System.out.println("访问者处理元素 B:" + elementB.operation());
}
}
// Element 接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素 A
class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation() {
return "元素 A 的操作";
}
}
// 具体元素 B
class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation() {
return "元素 B 的操作";
}
}
// 对象结构
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void add(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// 测试类
public class TestVisitorPattern {
public static void main(String[] args) {
ObjectStructure structure = new ObjectStructure();
structure.add(new ConcreteElementA());
structure.add(new ConcreteElementB());
Visitor visitor = new ConcreteVisitor();
structure.accept(visitor);
}
}
7.4 访问者模式的使用场景
- 对象结构稳定,但需要经常定义新的操作。
- 需要对多个不相关的类执行某些公共逻辑,又不想在每个类中都实现该逻辑。
- 操作依赖对象的状态,但不希望这些操作污染类本身。
7.5 访问者模式的优缺点
优点 | 缺点 |
---|---|
增加新的访问操作容易,符合开闭原则。 | 如果对象结构频繁变化(如新增元素类型),则维护困难。 |
操作集中管理,便于扩展和维护。 | 具体元素必须暴露自身细节给访问者,破坏封装性。 |
八 备忘录模式
- 备忘录模式(Memento Pattern)是行为型设计模式之一,用于在不破坏对象封装性的前提下,捕获并保存对象的内部状态,以便以后可以恢复到该状态。
- 备忘录模式通过将对象的状态存储为备忘录对象,实现了对象状态的保存与恢复。它广泛应用于需要撤销/重做功能的场景,例如文本编辑器、游戏存档等。虽然备忘录模式具有良好的封装性,但也需要注意内存占用问题。
8.1 备忘录模式的核心思想
- 保存对象的状态:将对象的状态保存为一个备忘录对象。
- 恢复对象的状态:通过备忘录对象还原对象的内部状态。
- 不暴露对象的内部细节:通过封装机制,避免直接访问对象的私有数据。
8.2 备忘录模式的核心角色
备忘录模式包含以下三个主要角色:
角色 | 职责 |
---|---|
Originator (发起人) |
创建一个备忘录来记录当前对象的状态,并可以从备忘录中恢复状态。 |
Memento (备忘录) |
存储发起人的状态,通常是一个不可变对象。 |
Caretaker (管理者) |
负责保存和提供备忘录,但不能修改备忘录的内容。 |
8.3 备忘录模式的代码实现
- 简单的 Java 实现示例
java
// Memento: 备忘录类
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Originator: 发起人类
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 restoreStateFromMemento(Memento memento) {
state = memento.getState();
}
}
// Caretaker: 管理者类
class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
public void add(Memento memento) {
mementoList.add(memento);
}
public Memento get(int index) {
return mementoList.get(index);
}
}
- 测试用例
java
public class MementoPatternDemo {
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");
System.out.println("Current State: " + originator.getState());
// 恢复到之前的状态
originator.restoreStateFromMemento(caretaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.restoreStateFromMemento(caretaker.get(1));
System.out.println("Second saved State: " + originator.getState());
}
}
bash
Current State: State #3
First saved State: State #1
Second saved State: State #2
8.4 备忘录模式的优缺点
优点 | 缺点 |
---|---|
封装性好:不暴露对象的内部细节。 | 可能占用较多内存,特别是保存大量状态时。 |
支持状态回滚:方便实现撤销/重做功能。 | 如果状态频繁变化,管理备忘录可能变得复杂。 |
8.5 备忘录模式的应用场景
备忘录模式适用于以下场景:
- 需要保存对象的历史状态,以便后续恢复。
- 需要实现撤销/重做功能。
- 不希望暴露对象的内部状态,同时需要保存其状态。
九命令模式
-
命令模式(Command Pattern)是行为型设计模式之一,用于将请求封装为对象,从而实现请求的队列化、日志记录、撤销/重做操作等功能。以下是关键点:
-
命令模式将一个请求封装成一个对象,从而使用户能够用不同的请求对客户端进行参数化。
9.1 命令模式的核心角色
Command
接口:定义执行操作的公共方法(如execute()
)。ConcreteCommand
类:具体命令类,持有对接收者对象的引用,并实现在Command
接口中定义的方法。Receiver
接口:定义实际执行操作的对象接口。Invoker
类:持有命令对象,并调用其execute()
方法来触发请求。Client
类:负责创建具体的命令对象并绑定到Invoker
上。
9.2 命令模式的代码实现
java
// 定义命令接口
public interface Command {
void execute();
}
// 具体命令类
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
// 接收者类
public class Light {
public void on() {
System.out.println("Light is on");
}
public void off() {
System.out.println("Light is off");
}
}
// 调用者类
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // 输出 "Light is on"
}
}
9.3 命令模式的优点
- 解耦:请求发送者和接收者相互独立,只需通过命令对象沟通。
- 扩展性强:可以轻松新增新的命令类型而无需修改已有代码。
- 支持撤销/重做:通过记录命令历史,可以方便地实现这些功能。
9.4 命令模式的适用场景
- 需要支持事务回滚或日志记录的操作。
- 系统需要解耦请求的发送者与执行者。
- 提供命令队列处理,例如任务调度系统。
十 解释器模式
- 解释器模式(Interpreter Pattern)是行为型设计模式之一,它用于定义语言的文法,并解析执行该语言的句子或表达式。给定一个语言,定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子。
- 解释器模式适合处理小型、结构固定的文法,但在实际开发中由于其维护成本较高,通常结合其他方式(如脚本引擎、ANTLR 等工具)实现更复杂的语言解析。
10.1 解释器模式的核心角色
- 抽象表达式(Expression):定义解释操作的公共接口。
- 终结符表达式(Terminal Expression):实现与文法中终结符相关的解释操作。
- 非终结符表达式(Non-terminal Expression):对应文法中非终结符,通常包含多个子表达式,递归组合解释。
- 上下文环境(Context):包含解释器需要的全局信息,例如变量值、状态等。
- 客户端(Client):构建语法树并调用解释方法。
10.2 解释器模式的代码实现
- 一个简单的数学表达式解释器示例,支持加法和减法:
java
// 抽象表达式
interface Expression {
int interpret(Context context);
}
// 终结符表达式:数字
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret(Context context) {
return number;
}
}
// 终结符表达式:变量
class VariableExpression implements Expression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public int interpret(Context context) {
return context.getVariable(name);
}
}
// 非终结符表达式:加法
class AddExpression implements Expression {
private Expression left, right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 非终结符表达式:减法
class SubtractExpression implements Expression {
private Expression left, right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
// 上下文环境
class Context {
private Map<String, Integer> variables = new HashMap<>();
// 设置变量值
public void setVariable(String name, int value) {
variables.put(name, value);
}
// 获取变量值
public int getVariable(String name) {
Integer value = variables.get(name);
if (value == null) {
throw new IllegalArgumentException("变量 " + name + " 未定义");
}
return value;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
// 构建表达式:x + y - 3
Expression expr = new SubtractExpression(
new AddExpression(new VariableExpression("x"), new VariableExpression("y")),
new NumberExpression(3)
);
Context context = new Context();
context.setVariable("x", 10);
context.setVariable("y", 5);
int result = expr.interpret(context);
System.out.println("结果: " + result); // 输出 12
}
}
10.3 解释器模式的优缺点
优点 | 缺点 |
---|---|
易于扩展文法规则,符合开闭原则 | 类的数量多,系统复杂度高 |
实现了文法规则与解释的分离 | 对于复杂语法效率低 |
10.4 解释器模式的适用场景
- 需要构建一种小型语言或DSL(领域特定语言),如规则引擎、数学表达式计算等。
- 文法简单且性能要求不高时。
- 当语法规则的变化频率较低时。
10.5 解释器模式的实际应用
- 正则表达式解析
- SQL 解析
- XML/JSON 解析器
- 规则引擎(如配置规则表达式)
十一 中介模式
- 中介者模式(Mediator Pattern)是行为型设计模式之一,用于降低多个对象之间的直接耦合。它通过引入一个中介者对象来封装一系列对象的交互逻辑,使得各个对象不需要显式地相互引用,从而实现松耦合。
11.1 中介者模式的核心角色
- Mediator:中介者接口,定义了同事对象之间通信的方法。
- ConcreteMediator:具体中介者类,实现了Mediator接口,并协调各个同事对象之间的交互。
- Colleague:同事类接口或抽象类,通常包含一个对Mediator的引用,并通过Mediator进行通信。
- ConcreteColleague:具体的同事类,实现自己的业务逻辑,并通过Mediator与其他同事进行交互。
11.2 终结者模式的代码实现
java
// Mediator 接口
public interface Mediator {
void send(String message, Colleague colleague);
}
// ConcreteMediator 类
public 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 send(String message, Colleague colleague) {
if (colleague == colleagueA) {
colleagueB.receive(message);
} else if (colleague == colleagueB) {
colleagueA.receive(message);
}
}
}
// Colleague 抽象类
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void receive(String message);
}
// ConcreteColleagueA 类
public class ColleagueA extends Colleague {
public ColleagueA(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void receive(String message) {
System.out.println("ColleagueA received: " + message);
}
}
// ConcreteColleagueB 类
public class ColleagueB extends Colleague {
public ColleagueB(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void receive(String message) {
System.out.println("ColleagueB received: " + message);
}
}
// 使用示例
public class Client {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
ColleagueA colleagueA = new ColleagueA(mediator);
ColleagueB colleagueB = new ColleagueB(mediator);
mediator.setColleagueA(colleagueA);
mediator.setColleagueB(colleagueB);
colleagueA.send("Hello from ColleagueA");
colleagueB.send("Hi from ColleagueB");
}
}
11.3 中介者模式的应用场景
- 当多个对象之间存在复杂的交互逻辑时,使用中介者模式可以简化这些对象之间的关系。
- 在需要解耦系统中的组件时,例如GUI组件之间的通信、系统模块间的协调等。
- 中介者模式适用于需要集中控制交互逻辑的场景,避免对象之间直接依赖。
11.4 中介者模式的优缺点
优点
- 降低耦合度:对象之间不再直接通信,而是通过中介者进行交互,减少了对象之间的依赖关系。
- 提高可维护性:将交互逻辑集中在一个中介者中,便于维护和扩展。
- 增强可复用性 :同事对象可以独立变化,不会影响其他对象。
缺点 - 中介者复杂度增加:随着系统的复杂度增加,中介者的逻辑可能会变得非常复杂,难以维护。
- 性能问题:由于所有交互都必须通过中介者,可能会影响系统的性能。
11.5 中介者模式的适用性
- 当对象之间的交互复杂且难以管理时。
- 当希望减少对象之间的直接依赖时。
- 当需要集中管理多个对象之间的交互逻辑时。