java设计模式[4]之设计型模式

文章目录

  • [零 行为型模式概述](#零 行为型模式概述)
  • [一 观察者模式](#一 观察者模式)
    • [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.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 具体策略类CreditCardPaymentPayPalPayment)
      • [3.3.3 上下文类:`ShoppingCart`](#3.3.3 上下文类:ShoppingCart)
      • [3.3.4 测试用例](#3.3.4 测试用例)
    • [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();
    }
}
  • 执行结果

    bash 复制代码
    Subject: 发生了某些业务逻辑变化
    观察者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 模版方法模式的优缺点

优点:

  1. 封装不变部分,扩展可变部分:算法骨架固定,子类只需实现变化的部分。
  2. 提高代码复用性:公共逻辑在父类中实现,避免重复代码。
  3. 符合开闭原则:新增子类不影响已有逻辑。

缺点:

  1. 增加子类复杂度:每个不同实现都需要一个子类。
  2. 违反里氏替换原则(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 具体策略类CreditCardPaymentPayPalPayment

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 策略模式的经典应用

  1. 数据验证:Spring框架提供Validator接口,允许开发者定义验证规则。通过实现不同的验证策略(如电子邮件验证,值范围验证等),可以在不同场景中使用不同的验证器,提高代码的复用性和灵活性。
  2. 缓存管理:Spring Cache提供Cache接口,允许开发者定义缓存策略,可以实现不同的缓存策略(如LRU缓存,FIFO缓存),并在服务方法中使用@Cacheable注解来指定缓存策略,从而在不修改业务逻辑的情况下优化系统性能。
  3. 事务处理:Spring容器提供事务管理服务,允许开发者定义不同的事务策略,并在服务方法中使用@Transactional注解来指定事务策略,方便开发者在不同业务场景下灵活选择处理事务的方式。
  4. 依赖注入:Spring提供DI规范,允许开发者使用@Autowird注解将依赖注入类中。通过定义不同的依赖注入策略,实现在不修改代码的情况下灵活地管理依赖关系。
  5. 多种算法选择:策略模式还常用于动态选择多种算法的场景。如,在支付系统中,不同的支付方式可以对应不同的结算方法;在物流系统中,不同的车型可能对应不同的物流规则。通过定义抽象策略和具体策略类,可以在运行时根据需求选择合适的算法进行处理。
  6. 场景模式:在场景模拟中,如游戏开发、仿真实验等。根据不同的条件选择不同的算法或行为。策略模式可以将这些算法或行为封装成独立的策略类,并在运行时根据条件动态选择使用策略类。

3.7 和其他模式对比

模式 区别
状态模式 策略模式是无状态的,而状态模式内部维护状态变化
模板方法 模板方法是通过继承固定流程,策略是通过组合方式改变行为

四 责任链模式

  • 责任链模式(Chain of Responsibility Pattern)是行为型设计模式之一,它允许将请求沿着处理者对象链进行传递,并让每个处理者决定是否处理该请求。这种方式实现了请求的发送者和接收者之间的解耦。
  • 责任链模式适用于请求的处理流程不确定或需要动态配置的场景,能够有效实现请求与处理者的解耦,提升系统的灵活性和可维护性。

4.1 责任链模式的核心思想

  • 解耦请求发送者和处理者:发送者无需知道具体处理者,只需要将请求发送到链上的第一个节点。
  • 动态调整处理逻辑:通过改变链的结构,可以灵活地增加、删除或修改请求的处理逻辑。

4.2 责任链模式的核心角色

  1. Handler(抽象处理者):定义一个处理请求的接口,通常包含一个指向下一个处理者的引用。
  2. ConcreteHandler(具体处理者):实现具体的请求处理逻辑,如果自己无法处理,则转发给下一个处理者。
  3. 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-elseswitch-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() 方法,许多集合类(如 ListSet)都实现了它。
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 解释器模式的核心角色

  1. 抽象表达式(Expression):定义解释操作的公共接口。
  2. 终结符表达式(Terminal Expression):实现与文法中终结符相关的解释操作。
  3. 非终结符表达式(Non-terminal Expression):对应文法中非终结符,通常包含多个子表达式,递归组合解释。
  4. 上下文环境(Context):包含解释器需要的全局信息,例如变量值、状态等。
  5. 客户端(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 中介者模式的适用性

  • 当对象之间的交互复杂且难以管理时。
  • 当希望减少对象之间的直接依赖时。
  • 当需要集中管理多个对象之间的交互逻辑时。
相关推荐
星辰大海的精灵19 分钟前
Spring Boot 中 WebClient 的实践详解
java·spring boot·后端
Chan1624 分钟前
MYSQL进阶超详细总结2.0
java·数据库·后端·sql·mysql
Emma歌小白25 分钟前
查看JAR 包上传阿里云是否上传成功并运行
java
蓝胖子不会敲代码28 分钟前
跟着AI学习C# Day14
开发语言·学习·c#
HINOTOR_34 分钟前
DAY 35 模型可视化与推理
开发语言·python
白总Server37 分钟前
Web 架构之 GraphQL 与 REST API 对比与选型
java·大数据·前端·javascript·后端·架构·graphql
H2122021651 小时前
P7 QT项目----会学天气预报
开发语言·qt
zx_zx_1231 小时前
线程的学习
java·开发语言·学习
司铭鸿1 小时前
Java响应式编程:Project Reactor与WebFlux高并发实践
java·开发语言·算法·职场和发展·生活
飞翔的佩奇1 小时前
Java项目:基于SSM框架实现的学生二手书籍交易平台管理系统【ssm+B/S架构+源码+数据库+毕业论文+答辩PPT+任务书+开题】
java·数据库·mysql·架构·毕业设计·毕业论文·二手书籍