← 首页·文章列表

设计模式

设计模式是解决特定场景软件设计问题的最佳实践,核心价值是解耦、复用、可维护。本文按三大类梳理23种模式,每个模式配套「核心逻辑图+Java实战案例+代码片段」,兼顾面试考点与开发落地,避免纯抽象定义。

一、创建型模式(5种)

核心目标:封装对象创建过程,解耦创建与使用,提高灵活性。

1. 工厂模式(3种变体)

1.1 简单工厂模式

核心逻辑:一个工厂类根据参数,动态创建不同产品实例,隐藏创建细节。

![[Pasted_image_20260122202216.png]]

Java实战案例:后端数据处理场景中,根据数据类型参数,创建不同实体类对象封装数据。

// 产品接口:统一数据模型规范
public interface DataBean {}

// 具体产品1:天气数据实体
public class WeatherBean implements DataBean {
    private String temp; // 温度
    // getter/setter、构造方法
    public String getTemp() { return temp; }
    public void setTemp(String temp) { this.temp = temp; }
}

// 具体产品2:城市数据实体
public class CityBean implements DataBean {
    private String cityName; // 城市名
    // getter/setter、构造方法
    public String getCityName() { return cityName; }
    public void setCityName(String cityName) { this.cityName = cityName; }
}

// 简单工厂类:根据参数创建对应产品
public class WeatherFactory {
    public static final int TYPE_WEATHER = 1;
    public static final int TYPE_CITY = 2;

    public static DataBean createDataBean(int type) {
        switch (type) {
            case TYPE_WEATHER:
                return new WeatherBean(); // 创建天气对象
            case TYPE_CITY:
                return new CityBean(); // 创建城市对象
            default:
                throw new IllegalArgumentException("无效类型");
        }
    }
}

// 客户端使用(纯Java应用,非Android)
public class DataProcessor {
    public static void main(String[] args) {
        // 无需关注创建细节,通过工厂获取对象
        DataBean weatherBean = WeatherFactory.createDataBean(WeatherFactory.TYPE_WEATHER);
        DataBean cityBean = WeatherFactory.createDataBean(WeatherFactory.TYPE_CITY);
        
        // 模拟数据封装
        if (weatherBean instanceof WeatherBean) {
            ((WeatherBean) weatherBean).setTemp("25℃");
        }
        if (cityBean instanceof CityBean) {
            ((CityBean) cityBean).setCityName("北京");
        }
    }
}

优缺点&场景:优点是简化创建,客户端无需关注细节;缺点是新增产品需改工厂(违背开闭原则)。适合产品少、变更少的纯Java场景(如固定数据模型创建、工具类实例生成)。

1.2 工厂方法模式

核心逻辑:定义抽象工厂接口,每个具体产品对应一个具体工厂,新增产品只需加工厂,符合开闭原则。

![[Pasted_image_20260122202200.png]]

Java实战案例:后端数据持久层场景,针对MySQL、Oracle两种不同数据库,分别创建对应的数据封装对象工厂,适配不同数据源的数据格式规范。

// 产品接口:统一数据模型规范
public interface DataBean {}

// 具体产品1:MySQL数据源封装对象
public class MysqlDataBean implements DataBean {
    private String mysqlData;
    // getter/setter、构造方法
    public String getMysqlData() { return mysqlData; }
    public void setMysqlData(String mysqlData) { this.mysqlData = mysqlData; }
}

// 具体产品2:Oracle数据源封装对象
public class OracleDataBean implements DataBean {
    private String oracleData;
    // getter/setter、构造方法
    public String getOracleData() { return oracleData; }
    public void setOracleData(String oracleData) { this.oracleData = oracleData; }
}

// 抽象工厂接口
public interface DataBeanFactory {
    DataBean createDataBean();
}

// 具体工厂1:创建MySQL数据对象
public class MysqlDataFactory implements DataBeanFactory {
    @Override
    public DataBean createDataBean() {
        return new MysqlDataBean();
    }
}

// 具体工厂2:创建Oracle数据对象
public class OracleDataFactory implements DataBeanFactory {
    @Override
    public DataBean createDataBean() {
        return new OracleDataBean();
    }
}

// 客户端使用(纯Java后端服务)
public class DataService {
    public static void main(String[] args) {
        // 切换工厂即可适配不同数据源,无需修改核心逻辑
        DataBeanFactory factory = new MysqlDataFactory();
        DataBean mysqlData = factory.createDataBean();
        
        factory = new OracleDataFactory();
        DataBean oracleData = factory.createDataBean();
        
        // 模拟数据封装
        ((MysqlDataBean) mysqlData).setMysqlData("MySQL数据库数据");
        ((OracleDataBean) oracleData).setOracleData("Oracle数据库数据");
    }
}

优缺点&场景:优点是符合开闭原则,扩展灵活;缺点是类数量膨胀(产品+工厂)。适合纯Java中产品多、独立性强的场景(如多数据源对象创建、不同格式数据解析器生成)。

1.3 抽象工厂模式

核心逻辑:抽象工厂创建一组相关的产品族,而非单一产品,保证产品族兼容性。

![[Pasted_image_20260122202135.png]]

Java实战案例:后端国际化数据处理服务,区分国内/国外数据产品族(配套的基础数据+扩展数据封装),适配不同地区的字段规范与展示需求。

// 产品族1:天气数据接口
public interface WeatherBean {
    void showWeatherInfo();
}
// 产品族2:城市数据接口
public interface CityBean {
    void showCityInfo();
}

// 具体产品:国内天气/城市
public class ChinaWeatherBean implements WeatherBean {
    private String temp;
    @Override
    public void showWeatherInfo() {
        System.out.println("国内温度:" + temp);
    }
    // getter/setter、构造方法
}
public class ChinaCityBean implements CityBean {
    private String cityName;
    @Override
    public void showCityInfo() {
        System.out.println("国内城市:" + cityName);
    }
    // getter/setter、构造方法
}

// 具体产品:国外天气/城市
public class ForeignWeatherBean implements WeatherBean {
    private String temp;
    private String unit; // 国外温度单位(华氏度)
    @Override
    public void showWeatherInfo() {
        System.out.println("Foreign Temperature:" + temp + unit);
    }
    // getter/setter、构造方法
}
public class ForeignCityBean implements CityBean {
    private String cityName;
    private String country; // 国外城市所属国家
    @Override
    public void showCityInfo() {
        System.out.println("Foreign City:" + cityName + "," + country);
    }
    // getter/setter、构造方法
}

// 抽象工厂:定义产品族创建方法
public interface WeatherProductFactory {
    WeatherBean createWeatherBean();
    CityBean createCityBean();
}

// 具体工厂1:国内产品族
public class ChinaWeatherFactory implements WeatherProductFactory {
    @Override
    public WeatherBean createWeatherBean() {
        return new ChinaWeatherBean();
    }
    @Override
    public CityBean createCityBean() {
        return new ChinaCityBean();
    }
}

// 具体工厂2:国外产品族
public class ForeignWeatherFactory implements WeatherProductFactory {
    @Override
    public WeatherBean createWeatherBean() {
        return new ForeignWeatherBean();
    }
    @Override
    public CityBean createCityBean() {
        return new ForeignCityBean();
    }
}

// 客户端使用(纯Java后端服务)
public class InternationalDataProcessor {
    public static void main(String[] args) {
        // 获取国内产品族
        WeatherProductFactory chinaFactory = new ChinaWeatherFactory();
        WeatherBean chinaWeather = chinaFactory.createWeatherBean();
        CityBean chinaCity = chinaFactory.createCityBean();
        
        // 模拟数据赋值与展示
        ((ChinaWeatherBean) chinaWeather).setTemp("25℃");
        ((ChinaCityBean) chinaCity).setCityName("北京");
        chinaWeather.showWeatherInfo();
        chinaCity.showCityInfo();
    }
}

优缺点&场景:优点是保证产品族兼容,扩展产品族灵活;缺点是扩展单产品困难。适合纯Java中需一组关联产品的场景(如国际化配套数据创建、多版本功能模块生成)。

2. 单例模式

核心逻辑:确保类仅一个实例,提供全局访问点,避免重复创建消耗资源。

Java实战案例:后端日志工具类(全局统一记录系统操作日志)、数据库连接池(控制连接数量避免资源耗尽),这类场景需强制保证全局唯一实例,杜绝重复创建导致的资源浪费与数据不一致问题。

// 单例模式:饿汉式(线程安全,加载即初始化)
public class LoggerUtil {
    // 私有静态实例,类加载时直接初始化
    private static final LoggerUtil INSTANCE = new LoggerUtil();
    
    // 私有构造方法,禁止外部实例化
    private LoggerUtil() {}
    
    // 公共静态方法,提供全局访问点
    public static LoggerUtil getInstance() {
        return INSTANCE;
    }
    
    // 核心业务方法:记录日志
    public void log(String message) {
        System.out.println("[" + System.currentTimeMillis() + "] " + message);
    }
}

// 单例模式:懒汉式(双重检查锁,线程安全+延迟加载)
public class DbConnectionPool {
    // 私有静态实例,volatile保证可见性与禁止指令重排
    private static volatile DbConnectionPool INSTANCE;
    
    // 私有构造方法,初始化连接池资源
    private DbConnectionPool() {
        // 模拟初始化数据库连接
        System.out.println("初始化数据库连接池,创建10个连接");
    }
    
    // 双重检查锁,保证高效且线程安全
    public static DbConnectionPool getInstance() {
        if (INSTANCE == null) {
            synchronized (DbConnectionPool.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DbConnectionPool();
                }
            }
        }
        return INSTANCE;
    }
    
    // 核心业务方法:获取连接
    public String getConnection() {
        return "获取数据库连接:" + System.currentTimeMillis();
    }
}

// 客户端使用
public class ServerApplication {
    public static void main(String[] args) {
        // 日志工具类使用
        LoggerUtil logger = LoggerUtil.getInstance();
        logger.log("系统启动成功");
        
        // 数据库连接池使用
        DbConnectionPool pool = DbConnectionPool.getInstance();
        String connection = pool.getConnection();
        System.out.println(connection);
        
        // 验证单例唯一性
        LoggerUtil logger2 = LoggerUtil.getInstance();
        System.out.println("日志工具类实例是否唯一:" + (logger == logger2));
        
        DbConnectionPool pool2 = DbConnectionPool.getInstance();
        System.out.println("连接池实例是否唯一:" + (pool == pool2));
    }
}

核心逻辑图:

![[Pasted_image_20260122202413.png]]

优缺点&场景:优点是控制实例数量、节约资源、保证数据一致;缺点是扩展性差,不适用于多线程高并发场景(需额外处理线程安全)。适合纯Java中需全局唯一实例的场景(日志工具、连接池、配置管理器等)。

3. 建造者模式

核心逻辑:将复杂对象的构建与表示分离,通过分步构建、统一组装,生成不同配置的对象,解决复杂对象创建时参数过多、配置混乱问题。

![[Pasted_image_20260122202501.png]]

Java实战案例:后端订单生成场景,订单包含基础信息(编号、金额)、扩展信息(收货地址、支付方式),通过建造者分步构建不同类型订单(普通订单、VIP订单)。

// 复杂产品:订单类
public class Order {
    private String orderNo; // 订单编号
    private double amount; // 订单金额
    private String address; // 收货地址(可选)
    private String payType; // 支付方式(可选)

    // 私有构造,仅允许建造者访问
    private Order(Builder builder) {
        this.orderNo = builder.orderNo;
        this.amount = builder.amount;
        this.address = builder.address;
        this.payType = builder.payType;
    }

    // 静态建造者内部类
    public static class Builder {
        // 必传参数
        private final String orderNo;
        private final double amount;
        // 可选参数
        private String address;
        private String payType;

        // 构造方法接收必传参数
        public Builder(String orderNo, double amount) {
            this.orderNo = orderNo;
            this.amount = amount;
        }

        // 分步设置可选参数,返回自身实现链式调用
        public Builder setAddress(String address) {
            this.address = address;
            return this;
        }

        public Builder setPayType(String payType) {
            this.payType = payType;
            return this;
        }

        // 构建产品
        public Order build() {
            return new Order(this);
        }
    }

    // 业务方法
    public void showOrderInfo() {
        System.out.println("订单编号:" + orderNo + ",金额:" + amount + ",地址:" + address + ",支付方式:" + payType);
    }
}

// 客户端使用(无需指挥者,简化版建造者,实际可加指挥者统一构建逻辑)
public class OrderService {
    public static void main(String[] args) {
        // 构建普通订单(含必选+部分可选参数)
        Order normalOrder = new Order.Builder("ORDER001", 299.9)
                .setAddress("北京市朝阳区")
                .setPayType("支付宝")
                .build();

        // 构建VIP订单(不同配置)
        Order vipOrder = new Order.Builder("ORDER002", 5999.9)
                .setAddress("上海市浦东新区")
                .setPayType("微信支付")
                .build();

        normalOrder.showOrderInfo();
        vipOrder.showOrderInfo();
    }
}

优缺点&场景:优点是分离构建与表示、支持链式调用、参数配置清晰;缺点是类结构复杂(多建造者类)。适合纯Java中复杂对象创建(订单、用户信息、配置类等参数多的场景)。

4. 原型模式

核心逻辑:通过复制已有实例(原型)创建新对象,避免重复执行复杂初始化逻辑,提高创建效率,分为浅克隆与深克隆。

暂时无法在豆包文档外展示此内容

Java实战案例:后端批量生成报表场景,报表基础模板(标题、格式)固定,仅数据不同,通过克隆原型模板快速生成多个报表,减少重复初始化。

import java.io.*;

// 原型类:报表模板(实现Cloneable接口支持克隆)
public class ReportTemplate implements Cloneable, Serializable {
    private String title; // 报表标题(基本类型)
    private ReportData data; // 报表数据(引用类型)

    // 构造方法:初始化模板
    public ReportTemplate(String title, ReportData data) {
        this.title = title;
        this.data = data;
        // 模拟复杂初始化逻辑(如读取模板文件、初始化格式)
        System.out.println("报表模板初始化完成(耗时操作)");
    }

    // 浅克隆:默认clone(),引用类型共享
    @Override
    protected ReportTemplate clone() throws CloneNotSupportedException {
        return (ReportTemplate) super.clone();
    }

    // 深克隆:通过序列化实现,引用类型独立
    public ReportTemplate deepClone() throws IOException, ClassNotFoundException {
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (ReportTemplate) ois.readObject();
    }

    // getter/setter
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public ReportData getData() { return data; }
    public void setData(ReportData data) { this.data = data; }
}

// 引用类型:报表数据(需实现Serializable支持深克隆)
class ReportData implements Serializable {
    private String content;

    public ReportData(String content) {
        this.content = content;
    }

    // getter/setter
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }
}

// 客户端使用
public class ReportService {
    public static void main(String[] args) throws Exception {
        // 1. 创建原型实例(仅初始化一次,耗时操作)
        ReportData prototypeData = new ReportData("原型报表数据");
        ReportTemplate prototype = new ReportTemplate("月度报表模板", prototypeData);

        // 2. 浅克隆
        ReportTemplate shallowClone = prototype.clone();
        shallowClone.setTitle("浅克隆月度报表");
        shallowClone.getData().setContent("浅克隆报表数据");
        // 验证:原型与浅克隆的引用类型共享
        System.out.println("原型数据与浅克隆数据是否相同:" + (prototype.getData() == shallowClone.getData()));

        // 3. 深克隆
        ReportTemplate deepClone = prototype.deepClone();
        deepClone.setTitle("深克隆月度报表");
        deepClone.getData().setContent("深克隆报表数据");
        // 验证:原型与深克隆的引用类型独立
        System.out.println("原型数据与深克隆数据是否相同:" + (prototype.getData() == deepClone.getData()));
    }
}

优缺点&场景:优点是避免重复初始化、提高创建效率;缺点是深克隆实现复杂。适合纯Java中对象初始化成本高、需批量创建相似对象的场景(报表、缓存对象、复杂POJO)。

二、结构型模式(7种)

核心目标:通过类或对象的组合,优化系统结构,实现功能复用与解耦,适配不同场景的结构需求。

1. 适配器模式

核心逻辑:将一个类的接口转换成客户端期望的另一个接口,解决不同接口间的兼容性问题,分为类适配器与对象适配器。

![[Pasted_image_20260122202614.png]]

Java实战案例:后端系统集成场景,旧系统支付接口(Adaptee)与新系统支付标准接口(Target)不兼容,通过适配器转换接口,实现旧接口复用。

// 目标接口:新系统支付标准接口
public interface Payment {
    void pay(double amount); // 新接口方法:支付指定金额
}

// 适配者:旧系统支付接口(接口不兼容,需适配)
public class OldPaymentSystem {
    // 旧接口方法:参数与目标接口不同
    public void doPay(String money) {
        System.out.println("旧系统支付:" + money + "元");
    }
}

// 适配器:对象适配器(推荐,通过组合适配者实现)
public class PaymentAdapter implements Payment {
    private OldPaymentSystem oldPaymentSystem;

    // 注入适配者实例
    public PaymentAdapter(OldPaymentSystem oldPaymentSystem) {
        this.oldPaymentSystem = oldPaymentSystem;
    }

    // 转换接口,适配旧系统方法
    @Override
    public void pay(double amount) {
        // 类型转换:新接口double -> 旧接口String
        String money = String.valueOf(amount);
        oldPaymentSystem.doPay(money);
    }
}

// 客户端使用(新系统调用)
public class PaymentService {
    public static void main(String[] args) {
        // 初始化旧系统支付
        OldPaymentSystem oldSystem = new OldPaymentSystem();
        // 通过适配器适配新接口
        Payment payment = new PaymentAdapter(oldSystem);
        // 新系统按标准接口调用
        payment.pay(299.9);
    }
}

优缺点&场景:优点是复用旧接口、解耦适配逻辑;缺点是增加系统复杂度。适合纯Java中接口不兼容场景(系统集成、旧代码复用、第三方组件适配)。

2. 装饰器模式

核心逻辑:动态给对象添加额外功能,不改变原类结构,通过组合替代继承,实现功能的灵活扩展。

![[Pasted_image_20260122202651.png]]

Java实战案例:后端日志打印场景,基础日志仅输出文本,通过装饰器动态添加时间戳、日志级别、异常堆栈等功能,灵活组合扩展。

// 抽象组件:日志接口
public interface Logger {
    void log(String message);
}

// 具体组件:基础日志(核心功能)
public class BasicLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.print(message); // 仅输出文本
    }
}

// 装饰器抽象类(实现日志接口,持有组件实例)
public abstract class LoggerDecorator implements Logger {
    protected Logger logger;

    public LoggerDecorator(Logger logger) {
        this.logger = logger;
    }

    @Override
    public abstract void log(String message);
}

// 具体装饰器1:添加时间戳
public class TimeLoggerDecorator extends LoggerDecorator {
    public TimeLoggerDecorator(Logger logger) {
        super(logger);
    }

    @Override
    public void log(String message) {
        String time = "[" + System.currentTimeMillis() + "] ";
        logger.log(time + message); // 先加时间戳,再调用核心功能
    }
}

// 具体装饰器2:添加日志级别
public class LevelLoggerDecorator extends LoggerDecorator {
    private String level;

    public LevelLoggerDecorator(Logger logger, String level) {
        super(logger);
        this.level = level;
    }

    @Override
    public void log(String message) {
        String levelStr = "[" + level + "] ";
        logger.log(levelStr + message); // 先加级别,再调用核心/装饰后功能
    }
}

// 客户端使用(组合装饰器)
public class LoggerService {
    public static void main(String[] args) {
        // 基础日志
        Logger basicLogger = new BasicLogger();
        // 装饰器组合:基础日志 + 时间戳 + 错误级别
        Logger errorLogger = new LevelLoggerDecorator(new TimeLoggerDecorator(basicLogger), "ERROR");
        // 装饰后功能
        errorLogger.log("系统异常:数据库连接失败");
    }
}

优缺点&场景:优点是动态扩展功能、组合灵活;缺点是装饰器类过多易复杂。适合纯Java中需灵活扩展功能的场景(日志、IO流、缓存增强等)。

3. 代理模式

核心逻辑:为目标对象提供一个代理对象,由代理对象控制对目标对象的访问,可在访问前后添加额外逻辑(增强、控制),分为静态代理与动态代理。

![[Pasted_image_20260122202723.png]]

Java实战案例:后端接口权限控制场景,通过代理对目标接口方法进行权限校验,无权限则拒绝访问,不修改目标接口代码。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 目标接口:用户服务
public interface UserService {
    void queryUser(String userId);
    void deleteUser(String userId);
}

// 目标对象:用户服务实现
public class UserServiceImpl implements UserService {
    @Override
    public void queryUser(String userId) {
        System.out.println("查询用户信息,用户ID:" + userId);
    }

    @Override
    public void deleteUser(String userId) {
        System.out.println("删除用户,用户ID:" + userId);
    }
}

// 动态代理:JDK动态代理(基于接口)
public class AuthProxyHandler implements InvocationHandler {
    private Object target; // 目标对象

    public AuthProxyHandler(Object target) {
        this.target = target;
    }

    // 代理逻辑:权限校验
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:权限校验(仅管理员可删除,查询无限制)
        String methodName = method.getName();
        if ("deleteUser".equals(methodName)) {
            String role = "user"; // 模拟当前用户角色,实际从会话获取
            if (!"admin".equals(role)) {
                throw new RuntimeException("无权限删除用户");
            }
        }
        // 调用目标对象方法
        Object result = method.invoke(target, args);
        // 后置增强:日志记录(可选)
        System.out.println("方法调用完成:" + methodName);
        return result;
    }

    // 获取代理对象
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new AuthProxyHandler(target)
        );
    }
}

// 客户端使用
public class UserServiceClient {
    public static void main(String[] args) {
        // 目标对象
        UserService userService = new UserServiceImpl();
        // 获取代理对象
        UserService proxy = (UserService) AuthProxyHandler.getProxy(userService);

        // 调用查询方法(无权限校验)
        proxy.queryUser("1001");

        // 调用删除方法(普通用户无权限,抛异常)
        try {
            proxy.deleteUser("1001");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

优缺点&场景:优点是解耦增强逻辑与核心业务、支持动态扩展;缺点是动态代理仅支持接口。适合纯Java中需控制访问、增强功能的场景(权限控制、事务管理、日志监控)。

4. 桥接模式

核心逻辑:将抽象部分与实现部分分离,使两者可独立扩展,通过组合替代继承,解决多维度变化导致的类爆炸问题。 ![[Pasted_image_20260122202737.png]]

Java实战案例:后端消息发送场景,消息类型(普通消息、紧急消息)与发送方式(短信、邮件)为两个独立维度,通过桥接模式实现多维度灵活组合。

// 实现维度:消息发送方式接口(Implementor)
public interface MessageSender {
    void send(String content); // 发送消息核心方法
}

// 具体实现1:短信发送
public class SmsSender implements MessageSender {
    @Override
    public void send(String content) {
        System.out.println("短信发送:" + content);
    }
}

// 具体实现2:邮件发送
public class EmailSender implements MessageSender {
    @Override
    public void send(String content) {
        System.out.println("邮件发送:" + content);
    }
}

// 抽象维度:消息抽象类(Abstraction)
public abstract class Message {
    protected MessageSender sender; // 持有实现维度引用(桥接核心)

    // 注入发送方式,解耦抽象与实现
    public Message(MessageSender sender) {
        this.sender = sender;
    }

    public abstract void sendMessage(String content); // 抽象发送方法
}

// 扩展抽象1:普通消息
public class NormalMessage extends Message {
    public NormalMessage(MessageSender sender) {
        super(sender);
    }

    @Override
    public void sendMessage(String content) {
        System.out.println("【普通消息】");
        sender.send(content); // 调用实现维度方法
    }
}

// 扩展抽象2:紧急消息
public class EmergencyMessage extends Message {
    public EmergencyMessage(MessageSender sender) {
        super(sender);
    }

    @Override
    public void sendMessage(String content) {
        System.out.println("【紧急消息】(重复发送3次)");
        // 增强逻辑:紧急消息重复发送
        for (int i = 0; i < 3; i++) {
            sender.send(content);
        }
    }
}

// 客户端使用
public class MessageService {
    public static void main(String[] args) {
        // 组合1:普通消息+短信发送
        Message normalSms = new NormalMessage(new SmsSender());
        normalSms.sendMessage("您有一条新通知");

        // 组合2:紧急消息+邮件发送
        Message emergencyEmail = new EmergencyMessage(new EmailSender());
        emergencyEmail.sendMessage("系统异常,请立即处理");
    }
}

优缺点&场景:优点是分离多维度变化、扩展灵活、减少类数量;缺点是增加系统复杂度,需理解抽象与实现分离逻辑。适合纯Java中多维度独立变化的场景(消息发送、日志输出、支付组合等)。

5. 组合模式

核心逻辑:将对象组合成树形结构,使单个对象(叶子)和组合对象(容器)具有一致的访问接口,统一处理树形结构中的所有元素。

暂时无法在豆包文档外展示此内容

Java实战案例:后端组织架构管理场景,部门(容器)可包含子部门(容器)和员工(叶子),通过组合模式统一查询部门/员工信息、计算总人数。

// 抽象组件:组织节点(Component)
public abstract class OrganizationNode {
    protected String name;

    public OrganizationNode(String name) {
        this.name = name;
    }

    // 统一方法:显示节点信息
    public abstract void showInfo();

    // 容器节点需实现的方法(叶子节点空实现)
    public void addNode(OrganizationNode node) {
        throw new UnsupportedOperationException("叶子节点不支持添加操作");
    }

    public void removeNode(OrganizationNode node) {
        throw new UnsupportedOperationException("叶子节点不支持删除操作");
    }

    // 统计节点数量(叶子为1,容器为自身+子节点总数)
    public abstract int countNode();
}

// 叶子节点:员工
public class Employee extends OrganizationNode {
    private String position; // 职位

    public Employee(String name, String position) {
        super(name);
        this.position = position;
    }

    @Override
    public void showInfo() {
        System.out.println("员工:" + name + ",职位:" + position);
    }

    @Override
    public int countNode() {
        return 1; // 员工自身为1个节点
    }
}

// 容器节点:部门
public class Department extends OrganizationNode {
    private List&lt;OrganizationNode&gt; children = new ArrayList<>(); // 子节点列表

    public Department(String name) {
        super(name);
    }

    @Override
    public void showInfo() {
        System.out.println("部门:" + name);
        // 遍历子节点,调用统一方法
        for (OrganizationNode node : children) {
            node.showInfo();
        }
    }

    @Override
    public void addNode(OrganizationNode node) {
        children.add(node);
    }

    @Override
    public void removeNode(OrganizationNode node) {
        children.remove(node);
    }

    @Override
    public int countNode() {
        int count = 1; // 自身为1个节点
        // 累加子节点数量
        for (OrganizationNode node : children) {
            count += node.countNode();
        }
        return count;
    }
}

// 客户端使用
public class OrganizationService {
    public static void main(String[] args) {
        // 构建组织架构树
        OrganizationNode company = new Department("总公司");
        OrganizationNode techDept = new Department("技术部");
        OrganizationNode hrDept = new Department("人事部");

        // 技术部添加员工
        techDept.addNode(new Employee("张三", "后端开发"));
        techDept.addNode(new Employee("李四", "前端开发"));

        // 人事部添加员工
        hrDept.addNode(new Employee("王五", "人事专员"));

        // 总公司添加部门
        company.addNode(techDept);
        company.addNode(hrDept);

        // 统一显示所有节点信息
        company.showInfo();

        // 统一统计总人数
        System.out.println("组织总人数:" + company.countNode());
    }
}

优缺点&场景:优点是统一访问接口、简化树形结构操作、易于扩展;缺点是叶子与容器职责模糊,部分操作需区分类型。适合纯Java中树形结构场景(组织架构、文件系统、菜单管理等)。

6. 外观模式

核心逻辑:为子系统中的一组接口提供一个统一的高层接口,简化客户端与子系统的交互,隐藏子系统复杂度,降低耦合。

![[Pasted_image_20260122202846.png]]

Java实战案例:后端用户注册场景,注册流程需调用用户服务、日志服务、邮件服务三个子系统,通过外观模式封装流程,客户端一键调用。

// 子系统1:用户服务(创建用户)
public class UserService {
    public void createUser(String username, String password) {
        System.out.println("创建用户:" + username);
    }
}

// 子系统2:日志服务(记录日志)
public class LogService {
    public void log(String message) {
        System.out.println("日志记录:" + message);
    }
}

// 子系统3:邮件服务(发送注册邮件)
public class EmailService {
    public void sendRegisterEmail(String email) {
        System.out.println("向" + email + "发送注册成功邮件");
    }
}

// 外观类:注册外观(封装子系统交互)
public class RegisterFacade {
    // 依赖子系统
    private UserService userService = new UserService();
    private LogService logService = new LogService();
    private EmailService emailService = new EmailService();

    // 封装注册流程,提供统一接口
    public void register(String username, String password, String email) {
        userService.createUser(username, password);
        logService.log("用户" + username + "注册成功");
        emailService.sendRegisterEmail(email);
    }
}

// 客户端使用
public class RegisterClient {
    public static void main(String[] args) {
        // 无需直接调用三个子系统,仅调用外观类方法
        RegisterFacade registerFacade = new RegisterFacade();
        registerFacade.register("zhangsan", "123456", "zhangsan@xxx.com");
    }
}

优缺点&场景:优点是简化客户端操作、隐藏子系统复杂度、降低耦合;缺点是外观类可能成为全能类,违背单一职责。适合纯Java中多子系统协同场景(注册流程、订单提交、系统启动等)。

7. 享元模式

核心逻辑:运用共享技术复用大量相似对象,减少内存占用,将对象的公共属性(内部状态)与可变属性(外部状态)分离,共享内部状态。

![[Pasted_image_20260122202901.png]]

Java实战案例:后端棋子游戏场景,棋盘上大量棋子(黑棋、白棋)仅颜色(内部状态)固定,位置(外部状态)可变,通过享元模式复用棋子对象,减少内存消耗。

// 享元接口
public interface ChessPiece {
    // 传入外部状态(位置),执行操作
    void display(int x, int y);
}

// 具体享元:黑棋(内部状态固定)
public class BlackChess implements ChessPiece {
    // 内部状态:颜色(共享,固定)
    private final String color = "黑色";

    @Override
    public void display(int x, int y) {
        System.out.println("放置" + color + "棋子,位置:(" + x + "," + y + ")");
    }
}

// 具体享元:白棋(内部状态固定)
public class WhiteChess implements ChessPiece {
    // 内部状态:颜色(共享,固定)
    private final String color = "白色";

    @Override
    public void display(int x, int y) {
        System.out.println("放置" + color + "棋子,位置:(" + x + "," + y + ")");
    }
}

// 享元工厂:管理享元对象缓存与创建
public class ChessPieceFactory {
    // 缓存池:存储共享享元对象
    private static Map<String, ChessPiece&gt; chessPool = new HashMap<>();

    // 获取享元对象,不存在则创建并缓存
    public static ChessPiece getChessPiece(String color) {
        ChessPiece chessPiece = chessPool.get(color);
        if (chessPiece == null) {
            switch (color) {
                case "黑色":
                    chessPiece = new BlackChess();
                    break;
                case "白色":
                    chessPiece = new WhiteChess();
                    break;
                default:
                    throw new IllegalArgumentException("无效棋子颜色");
            }
            chessPool.put(color, chessPiece);
            System.out.println("创建" + color + "棋子并缓存");
        } else {
            System.out.println("复用缓存中的" + color + "棋子");
        }
        return chessPiece;
    }
}

// 客户端使用
public class ChessGame {
    public static void main(String[] args) {
        // 多次获取黑棋、白棋,仅首次创建,后续复用
        ChessPiece black1 = ChessPieceFactory.getChessPiece("黑色");
        black1.display(1, 1);

        ChessPiece black2 = ChessPieceFactory.getChessPiece("黑色");
        black2.display(1, 3);

        ChessPiece white1 = ChessPieceFactory.getChessPiece("白色");
        white1.display(2, 2);

        ChessPiece white2 = ChessPieceFactory.getChessPiece("白色");
        white2.display(2, 4);
    }
}

优缺点&场景:优点是减少对象创建、节省内存;缺点是分离内部/外部状态,增加系统复杂度。适合纯Java中大量相似对象场景(游戏棋子、字符缓存、图标资源等)。

三、行为型模式(11种)

核心目标:关注对象间的交互与职责分配,优化算法、请求传递、状态管理等行为逻辑,实现行为复用与解耦。

1. 策略模式

核心逻辑:定义一系列算法,将每个算法封装成独立类,使算法可动态切换,且与使用算法的客户端解耦。

![[Pasted_image_20260122202942.png]]

Java实战案例:后端支付场景,支持支付宝、微信、银联三种支付算法,通过策略模式动态切换支付方式,便于扩展新支付渠道。

// 策略接口:支付策略
public interface PaymentStrategy {
    void pay(double amount); // 支付算法核心方法
}

// 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("通过支付宝支付:" + amount + "元");
    }
}

// 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("通过微信支付:" + amount + "元");
    }
}

// 具体策略3:银联支付
public class UnionPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("通过银联支付:" + amount + "元");
    }
}

// 上下文:支付上下文(封装策略切换与调用)
public class PaymentContext {
    private PaymentStrategy strategy;

    // 注入策略,支持动态切换
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    // 调用策略算法
    public void executePay(double amount) {
        if (strategy == null) {
            throw new RuntimeException("请选择支付方式");
        }
        strategy.pay(amount);
    }
}

// 客户端使用
public class PaymentClient {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();
        double amount = 399.9;

        // 切换策略:支付宝支付
        context.setStrategy(new AlipayStrategy());
        context.executePay(amount);

        // 切换策略:微信支付
        context.setStrategy(new WechatPayStrategy());
        context.executePay(amount);
    }
}

优缺点&场景:优点是算法可动态切换、扩展灵活、解耦算法与客户端;缺点是策略类数量多,客户端需了解策略差异。适合纯Java中多种算法可选、需动态切换的场景(支付方式、排序算法、日志级别等)。

2. 模板方法模式

核心逻辑:定义一个算法的骨架(模板方法),将算法中的可变步骤延迟到子类实现,固定算法流程,灵活定制具体步骤。

暂时无法在豆包文档外展示此内容

Java实战案例:后端数据导出场景,导出流程(准备数据、导出文件、记录日志)固定,导出格式(Excel、CSV)可变,通过模板方法模式定制不同导出方式。

// 抽象类:数据导出模板
public abstract class DataExportTemplate {
    // 模板方法:定义算法骨架(流程固定,不可重写)
    public final void exportData() {
        prepareData(); // 固定步骤1:准备数据
        doExport();    // 可变步骤2:导出文件(子类实现)
        logExport();   // 固定步骤3:记录日志
    }

    // 固定步骤1:准备数据
    private void prepareData() {
        System.out.println("准备数据:查询数据库并封装");
    }

    // 可变步骤2:导出文件(抽象方法,子类定制)
    protected abstract void doExport();

    // 固定步骤3:记录日志
    private void logExport() {
        System.out.println("日志记录:数据导出完成");
    }
}

// 子类1:Excel导出
public class ExcelExport extends DataExportTemplate {
    @Override
    protected void doExport() {
        System.out.println("导出为Excel文件,格式:.xlsx");
    }
}

// 子类2:CSV导出
public class CsvExport extends DataExportTemplate {
    @Override
    protected void doExport() {
        System.out.println("导出为CSV文件,格式:.csv");
    }
}

// 客户端使用
public class ExportClient {
    public static void main(String[] args) {
        // Excel导出
        DataExportTemplate excelExport = new ExcelExport();
        excelExport.exportData();

        System.out.println("-------------------");

        // CSV导出
        DataExportTemplate csvExport = new CsvExport();
        csvExport.exportData();
    }
}

优缺点&场景:优点是固定算法流程、复用公共代码、扩展灵活;缺点是子类过多易导致类膨胀,模板方法不可修改。适合纯Java中算法流程固定、具体步骤可变的场景(数据导出、接口调用、业务流程处理等)。

3. 观察者模式

核心逻辑:定义对象间的一对多依赖关系,当被观察者(主题)状态变化时,自动通知所有观察者并更新,实现松耦合的通知机制。

暂时无法在豆包文档外展示此内容

Java实战案例:后端订单状态通知场景,订单(被观察者)状态变更为“已支付”“已发货”时,自动通知短信服务、日志服务、库存服务(观察者)执行对应操作。

import java.util.ArrayList;
import java.util.List;

// 观察者接口
public interface Observer {
    // 接收通知并更新(参数为被观察者状态)
    void update(String orderNo, String status);
}

// 具体观察者1:短信服务
public class SmsObserver implements Observer {
    @Override
    public void update(String orderNo, String status) {
        System.out.println("短信通知:订单" + orderNo + "状态变更为" + status);
    }
}

// 具体观察者2:日志服务
public class LogObserver implements Observer {
    @Override
    public void update(String orderNo, String status) {
        System.out.println("日志记录:订单" + orderNo + "状态变更为" + status);
    }
}

// 具体观察者3:库存服务
public class StockObserver implements Observer {
    @Override
    public void update(String orderNo, String status) {
        if ("已支付".equals(status)) {
            System.out.println("库存操作:订单" + orderNo + "已支付,扣减对应库存");
        }
    }
}

// 被观察者:订单主题
public class OrderSubject {
    // 观察者列表
    private List<Observer&gt; observers = new ArrayList<>();
    private String orderNo;
    private String status;

    public OrderSubject(String orderNo) {
        this.orderNo = orderNo;
    }

    // 注册观察者
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    // 移除观察者
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    // 通知所有观察者
    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(orderNo, status);
        }
    }

    // 设置订单状态(状态变化时触发通知)
    public void setStatus(String status) {
        this.status = status;
        notifyObservers();
    }
}

// 客户端使用
public class OrderClient {
    public static void main(String[] args) {
        // 创建被观察者:订单
        OrderSubject order = new OrderSubject("ORDER003");

        // 注册观察者
        order.registerObserver(new SmsObserver());
        order.registerObserver(new LogObserver());
        order.registerObserver(new StockObserver());

        // 变更订单状态,自动通知所有观察者
        System.out.println("=== 订单状态变更为:已支付 ===");
        order.setStatus("已支付");

        System.out.println("=== 订单状态变更为:已发货 ===");
        order.setStatus("已发货");
    }
}

优缺点&场景:优点是解耦主题与观察者、支持动态注册/移除、通知机制灵活;缺点是观察者过多时通知效率低,可能产生循环依赖。适合纯Java中一对多通知场景(订单状态、消息推送、事件监听等)。

4. 迭代器模式

核心逻辑:提供一种统一遍历聚合对象的方式,分离聚合对象的存储与遍历职责,使遍历逻辑独立于聚合结构,支持多种遍历方式。

暂时无法在豆包文档外展示此内容

Java实战案例:后端自定义容器场景,实现一个专属数据集合,通过迭代器模式提供统一遍历接口,支持正向、反向两种遍历方式,不暴露集合内部存储结构。

// 迭代器接口
public interface MyIterator<T> {
    boolean hasNext(); // 是否有下一个元素
    T next(); // 获取下一个元素
}

// 聚合接口
public interface MyAggregate<T> {
    MyIterator<T> createIterator(); // 创建迭代器
}

// 具体迭代器:正向迭代
public class ForwardIterator<T> implements MyIterator<T> {
    private MyList<T> list; // 聚合对象
    private int index = 0; // 遍历索引

    public ForwardIterator(MyList<T> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        return index < list.size();
    }

    @Override
    public T next() {
        if (hasNext()) {
            return list.get(index++);
        }
        throw new NoSuchElementException("无更多元素");
    }
}

// 具体迭代器:反向迭代
public class ReverseIterator<T> implements MyIterator<T> {
    private MyList<T> list;
    private int index;

    public ReverseIterator(MyList<T> list) {
        this.list = list;
        this.index = list.size() - 1;
    }

    @Override
    public boolean hasNext() {
        return index >= 0;
    }

    @Override
    public T next() {
        if (hasNext()) {
            return list.get(index--);
        }
        throw new NoSuchElementException("无更多元素");
    }
}

// 具体聚合:自定义列表
public class MyList<T> implements MyAggregate<T> {
    private Object[] elements; // 内部存储结构
    private int size = 0;

    public MyList(int capacity) {
        elements = new Object[capacity];
    }

    // 添加元素
    public void add(T element) {
        if (size < elements.length) {
            elements[size++] = element;
        } else {
            throw new IndexOutOfBoundsException("列表已满");
        }
    }

    // 获取指定索引元素(仅供迭代器访问,不对外暴露)
    public T get(int index) {
        if (index >= 0 && index < size) {
            return (T) elements[index];
        }
        throw new IndexOutOfBoundsException("索引越界");
    }

    // 获取元素数量
    public int size() {
        return size;
    }

    // 创建正向迭代器
    @Override
    public MyIterator<T> createIterator() {
        return new ForwardIterator<>(this);
    }

    // 额外提供反向迭代器创建方法
    public MyIterator<T> createReverseIterator() {
        return new ReverseIterator<>(this);
    }
}

// 客户端使用
public class IteratorClient {
    public static void main(String[] args) {
        MyList&lt;String&gt; list = new MyList<>(5);
        list.add("Java");
        list.add("设计模式");
        list.add("迭代器模式");

        // 正向遍历
        MyIterator<String> forwardIt = list.createIterator();
        System.out.println("正向遍历:");
        while (forwardIt.hasNext()) {
            System.out.println(forwardIt.next());
        }

        // 反向遍历
        MyIterator<String> reverseIt = list.createReverseIterator();
        System.out.println("\n反向遍历:");
        while (reverseIt.hasNext()) {
            System.out.println(reverseIt.next());
        }
    }
}

优缺点&场景:优点是分离存储与遍历、支持多种遍历方式、扩展灵活;缺点是增加类数量(迭代器+聚合)。适合纯Java中自定义聚合对象、需统一遍历接口的场景(自定义容器、树形结构遍历、复杂集合遍历)。

5. 责任链模式

核心逻辑:将请求的处理者连成一条链,请求沿链传递,直到有一个处理者处理该请求,避免请求发送者与接收者耦合,动态调整处理链路。 ![[Pasted_image_20260122203151.png]]

Java实战案例:后端接口权限校验场景,请求需经过普通用户校验、管理员校验、超级管理员校验三级链路,不同权限处理不同范围的请求,形成责任链。

// 请求类:封装请求信息
public class AuthRequest {
    private String userId; // 用户ID
    private String role; // 用户角色
    private String requestType; // 请求类型(查询/删除/修改)

    public AuthRequest(String userId, String role, String requestType) {
        this.userId = userId;
        this.role = role;
        this.requestType = requestType;
    }

    // getter
    public String getUserId() { return userId; }
    public String getRole() { return role; }
    public String getRequestType() { return requestType; }
}

// 处理者接口
public abstract class AuthHandler {
    protected AuthHandler nextHandler; // 下一个处理者

    // 设置下一个处理者,构建责任链
    public void setNextHandler(AuthHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 处理请求的抽象方法
    public abstract void handleRequest(AuthRequest request);
}

// 具体处理者1:普通用户处理器(仅处理查询请求)
public class UserHandler extends AuthHandler {
    @Override
    public void handleRequest(AuthRequest request) {
        if ("user".equals(request.getRole()) && "查询".equals(request.getRequestType())) {
            System.out.println("普通用户" + request.getUserId() + "处理查询请求");
        } else if (nextHandler != null) {
            // 无法处理,传递给下一个处理者
            nextHandler.handleRequest(request);
        } else {
            throw new RuntimeException("无对应处理器处理请求");
        }
    }
}

// 具体处理者2:管理员处理器(处理查询、修改请求)
public class AdminHandler extends AuthHandler {
    @Override
    public void handleRequest(AuthRequest request) {
        if ("admin".equals(request.getRole())) {
            if ("查询".equals(request.getRequestType()) || "修改".equals(request.getRequestType())) {
                System.out.println("管理员" + request.getUserId() + "处理" + request.getRequestType() + "请求");
            } else if (nextHandler != null) {
                nextHandler.handleRequest(request);
            } else {
                throw new RuntimeException("无对应处理器处理请求");
            }
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            throw new RuntimeException("无对应处理器处理请求");
        }
    }
}

// 具体处理者3:超级管理员处理器(处理所有请求)
public class SuperAdminHandler extends AuthHandler {
    @Override
    public void handleRequest(AuthRequest request) {
        if ("superAdmin".equals(request.getRole())) {
            System.out.println("超级管理员" + request.getUserId() + "处理" + request.getRequestType() + "请求");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            throw new RuntimeException("无对应处理器处理请求");
        }
    }
}

// 客户端使用:构建责任链并发起请求
public class AuthClient {
    public static void main(String[] args) {
        // 创建处理者
        AuthHandler userHandler = new UserHandler();
        AuthHandler adminHandler = new AdminHandler();
        AuthHandler superAdminHandler = new SuperAdminHandler();

        // 构建责任链:用户 -> 管理员 -> 超级管理员
        userHandler.setNextHandler(adminHandler);
        adminHandler.setNextHandler(superAdminHandler);

        // 发起不同请求
        AuthRequest request1 = new AuthRequest("1001", "user", "查询");
        userHandler.handleRequest(request1);

        AuthRequest request2 = new AuthRequest("1002", "admin", "修改");
        userHandler.handleRequest(request2);

        AuthRequest request3 = new AuthRequest("1003", "superAdmin", "删除");
        userHandler.handleRequest(request3);
    }
}

优缺点&场景:优点是解耦请求与处理者、动态调整链路、支持扩展;缺点是请求可能遍历全链,效率低,链路构建复杂。适合纯Java中多处理者处理同一请求、需动态分配责任的场景(权限校验、日志分级处理、异常处理链路)。

6. 命令模式

核心逻辑:将请求封装成命令对象,使请求的发起者与执行者解耦,支持命令的存储、撤销、队列执行等功能,通过命令对象传递请求。

暂时无法在豆包文档外展示此内容

Java实战案例:后端订单操作场景,将订单的创建、取消、支付操作封装成命令,通过调用者执行命令,支持命令的撤销与日志记录,解耦操作发起与执行逻辑。

// 接收者1:订单服务(执行具体操作)
public class OrderService {
    public void createOrder(String orderNo) {
        System.out.println("创建订单:" + orderNo);
    }

    public void cancelOrder(String orderNo) {
        System.out.println("取消订单:" + orderNo);
    }
}

// 接收者2:支付服务(执行支付操作)
public class PaymentService {
    public void payOrder(String orderNo, double amount) {
        System.out.println("支付订单" + orderNo + ",金额:" + amount + "元");
    }
}

// 命令接口
public interface OrderCommand {
    void execute(); // 执行命令
    void undo(); // 撤销命令
}

// 具体命令1:创建订单命令
public class CreateOrderCommand implements OrderCommand {
    private OrderService orderService;
    private String orderNo;

    public CreateOrderCommand(OrderService orderService, String orderNo) {
        this.orderService = orderService;
        this.orderNo = orderNo;
    }

    @Override
    public void execute() {
        orderService.createOrder(orderNo);
    }

    @Override
    public void undo() {
        orderService.cancelOrder(orderNo); // 撤销创建即取消订单
    }
}

// 具体命令2:支付订单命令
public class PayOrderCommand implements OrderCommand {
    private PaymentService paymentService;
    private String orderNo;
    private double amount;
    private boolean paid = false; // 支付状态,用于撤销判断

    public PayOrderCommand(PaymentService paymentService, String orderNo, double amount) {
        this.paymentService = paymentService;
        this.orderNo = orderNo;
        this.amount = amount;
    }

    @Override
    public void execute() {
        if (!paid) {
            paymentService.payOrder(orderNo, amount);
            paid = true;
        }
    }

    @Override
    public void undo() {
        if (paid) {
            System.out.println("撤销支付订单" + orderNo + ",金额:" + amount + "元(退款)");
            paid = false;
        }
    }
}

// 调用者:命令执行器
public class CommandInvoker {
    private OrderCommand command; // 持有当前命令
    private List&lt;OrderCommand&gt; commandHistory = new ArrayList<>(); // 命令历史,支持批量撤销

    // 设置命令
    public void setCommand(OrderCommand command) {
        this.command = command;
    }

    // 执行命令并记录历史
    public void executeCommand() {
        if (command != null) {
            command.execute();
            commandHistory.add(command);
        }
    }

    // 撤销上一条命令
    public void undoLastCommand() {
        if (!commandHistory.isEmpty()) {
            OrderCommand lastCommand = commandHistory.remove(commandHistory.size() - 1);
            lastCommand.undo();
        } else {
            throw new RuntimeException("无命令可撤销");
        }
    }
}

// 客户端使用
public class CommandClient {
    public static void main(String[] args) {
        // 初始化接收者
        OrderService orderService = new OrderService();
        PaymentService paymentService = new PaymentService();

        // 创建命令
        OrderCommand createCommand = new CreateOrderCommand(orderService, "ORDER004");
        OrderCommand payCommand = new PayOrderCommand(paymentService, "ORDER004", 299.9);

        // 初始化调用者
        CommandInvoker invoker = new CommandInvoker();

        // 执行创建命令
        invoker.setCommand(createCommand);
        invoker.executeCommand();

        // 执行支付命令
        invoker.setCommand(payCommand);
        invoker.executeCommand();

        // 撤销支付命令
        System.out.println("\n撤销上一条命令:");
        invoker.undoLastCommand();

        // 撤销创建命令
        System.out.println("撤销上一条命令:");
        invoker.undoLastCommand();
    }
}

优缺点&场景:优点是解耦发起者与执行者、支持命令撤销/队列/日志、扩展灵活;缺点是类数量膨胀(命令+接收者)。适合纯Java中需封装请求、支持撤销/日志的场景(订单操作、任务调度、遥控器功能、事务管理)。

7. 状态模式

核心逻辑:将对象的状态封装成独立状态类,对象状态变化时切换对应的状态类,使对象行为随状态动态改变,状态逻辑与对象本身分离。

暂时无法在豆包文档外展示此内容

Java实战案例:后端订单状态管理场景,订单包含“待支付”“已支付”“已发货”“已完成”四种状态,不同状态下执行不同操作(支付、发货、确认收货),状态变化时自动切换行为。

// 上下文:订单类(持有当前状态)
public class OrderContext {
    private OrderState currentState;
    private String orderNo;

    public OrderContext(String orderNo) {
        this.orderNo = orderNo;
        this.currentState = new PendingPayState(); // 初始状态:待支付
    }

    // 设置当前状态(状态切换)
    public void setState(OrderState state) {
        this.currentState = state;
    }

    // 获取订单号
    public String getOrderNo() {
        return orderNo;
    }

    // 委托当前状态执行支付操作
    public void pay() {
        currentState.pay(this);
    }

    // 委托当前状态执行发货操作
    public void ship() {
        currentState.ship(this);
    }

    // 委托当前状态执行确认收货操作
    public void confirmReceive() {
        currentState.confirmReceive(this);
    }
}

// 状态接口
public interface OrderState {
    void pay(OrderContext context); // 支付操作
    void ship(OrderContext context); // 发货操作
    void confirmReceive(OrderContext context); // 确认收货操作
}

// 具体状态1:待支付
public class PendingPayState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单" + context.getOrderNo() + "支付成功");
        context.setState(new PaidState()); // 切换状态为已支付
    }

    @Override
    public void ship(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "未支付,无法发货");
    }

    @Override
    public void confirmReceive(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "未支付,无法确认收货");
    }
}

// 具体状态2:已支付
public class PaidState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已支付,无需重复支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("订单" + context.getOrderNo() + "发货成功");
        context.setState(new ShippedState()); // 切换状态为已发货
    }

    @Override
    public void confirmReceive(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "未发货,无法确认收货");
    }
}

// 具体状态3:已发货
public class ShippedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已支付,无需重复支付");
    }

    @Override
    public void ship(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已发货,无需重复发货");
    }

    @Override
    public void confirmReceive(OrderContext context) {
        System.out.println("订单" + context.getOrderNo() + "确认收货成功");
        context.setState(new CompletedState()); // 切换状态为已完成
    }
}

// 具体状态4:已完成
public class CompletedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已完成,无需支付");
    }

    @Override
    public void ship(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已完成,无需发货");
    }

    @Override
    public void confirmReceive(OrderContext context) {
        throw new RuntimeException("订单" + context.getOrderNo() + "已完成,无需重复确认收货");
    }
}

// 客户端使用
public class StateClient {
    public static void main(String[] args) {
        OrderContext order = new OrderContext("ORDER005");

        // 执行状态操作,触发状态切换
        order.pay(); // 待支付 -> 已支付
        order.ship(); // 已支付 -> 已发货
        order.confirmReceive(); // 已发货 -> 已完成

        // 尝试执行已完成状态不支持的操作
        try {
            order.pay();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

优缺点&场景:优点是状态逻辑分离、状态切换清晰、扩展灵活;缺点是类数量膨胀(状态类过多)。适合纯Java中对象状态多、行为随状态变化的场景(订单状态、流程状态、设备状态管理)。

8. 备忘录模式

核心逻辑:在不破坏封装的前提下,捕获对象的内部状态并保存,以便后续恢复到该状态,实现对象状态的备份与回滚,分离状态存储与对象本身。

暂时无法在豆包文档外展示此内容

Java实战案例:后端文本编辑器场景,编辑器(发起人)可输入文本,通过备忘录备份当前文本状态,支持回滚到上一版本,管理者负责存储多个备份记录。

// 备忘录:存储文本状态(内部类,仅发起人可访问状态)
public class TextMemento {
    // 私有构造,仅发起人可创建
    private TextMemento(String content) {
        this.content = content;
    }

    private String content; // 存储的文本状态

    // 仅发起人可获取状态(通过内部类访问控制)
    private String getContent() {
        return content;
    }

    // 发起人:文本编辑器
    public static class TextEditor {
        private String currentContent; // 当前文本内容

        public void setContent(String content) {
            System.out.println("设置文本内容:" + content);
            this.currentContent = content;
        }

        // 创建备忘录,备份当前状态
        public TextMemento createMemento() {
            return new TextMemento(currentContent);
        }

        // 恢复状态
        public void restoreMemento(TextMemento memento) {
            this.currentContent = memento.getContent();
            System.out.println("恢复文本内容:" + currentContent);
        }

        // 获取当前内容
        public String getCurrentContent() {
            return currentContent;
        }
    }
}

// 管理者:备忘录管理类(存储多个备份)
public class MementoCaretaker {
    private List<TextMemento> mementoList = new ArrayList<>();

    // 保存备忘录
    public void saveMemento(TextMemento memento) {
        mementoList.add(memento);
        System.out.println("备份完成,当前备份数:" + mementoList.size());
    }

    // 获取指定索引的备忘录(回滚到对应版本)
    public TextMemento getMemento(int index) {
        if (index >= 0 &amp;&amp; index < mementoList.size()) {
            return mementoList.get(index);
        }
        throw new IndexOutOfBoundsException("备份索引越界");
    }

    // 获取上一个版本的备忘录
    public TextMemento getLastMemento() {
        if (!mementoList.isEmpty()) {
            return mementoList.get(mementoList.size() - 1);
        }
        throw new RuntimeException("无备份记录");
    }
}

// 客户端使用
public class MementoClient {
    public static void main(String[] args) {
        // 初始化发起人、管理者
        TextMemento.TextEditor editor = new TextMemento.TextEditor();
        MementoCaretaker caretaker = new MementoCaretaker();

        // 输入文本并备份
        editor.setContent("版本1:设计模式学习");
        caretaker.saveMemento(editor.createMemento());

        // 继续输入并备份
        editor.setContent("版本2:设计模式学习 - 备忘录模式");
        caretaker.saveMemento(editor.createMemento());

        // 继续输入
        editor.setContent("版本3:设计模式学习 - 备忘录模式实战");
        System.out.println("当前文本:" + editor.getCurrentContent());

        // 回滚到上一版本(版本2)
        editor.restoreMemento(caretaker.getLastMemento());
        System.out.println("回滚后文本:" + editor.getCurrentContent());

        // 回滚到版本1
        editor.restoreMemento(caretaker.getMemento(0));
        System.out.println("回滚后文本:" + editor.getCurrentContent());
    }
}

优缺点&场景:优点是备份与恢复灵活、不破坏封装;缺点是频繁备份消耗内存,备忘录状态过多易冗余。适合纯Java中需保存对象状态、支持回滚的场景(文本编辑、配置备份、事务回滚、游戏存档)。

9. 中介者模式

核心逻辑:定义一个中介者对象,封装多个对象间的交互关系,使对象间不直接通信,通过中介者间接交互,减少对象间耦合,集中管理交互逻辑。

暂时无法在豆包文档外展示此内容

Java实战案例:后端聊天系统场景,用户(同事对象)发送消息时不直接交互,通过聊天中介者转发消息,中介者负责维护用户列表、分发消息,支持一对一、群聊消息转发。

// 中介者接口
public interface ChatMediator {
    void registerUser(User user); // 注册用户
    void sendMessage(String message, User sender, User receiver); // 一对一消息
    void sendGroupMessage(String message, User sender); // 群聊消息
}

// 同事对象:用户
public class User {
    private String username;
    private ChatMediator mediator;

    public User(String username, ChatMediator mediator) {
        this.username = username;
        this.mediator = mediator;
        mediator.registerUser(this); // 注册到中介者
    }

    // 发送一对一消息
    public void sendTo(String message, User receiver) {
        System.out.println(username + " 发送给 " + receiver.getUsername() + ":" + message);
        mediator.sendMessage(message, this, receiver);
    }

    // 发送群聊消息
    public void sendGroup(String message) {
        System.out.println(username + " 发送群聊消息:" + message);
        mediator.sendGroupMessage(message, this);
    }

    // 接收消息
    public void receiveMessage(String message, User sender) {
        System.out.println(username + " 收到 " + sender.getUsername() + " 的消息:" + message);
    }

    // getter
    public String getUsername() {
        return username;
    }
}

// 具体中介者:聊天中介
public class ChatMediatorImpl implements ChatMediator {
    private List&lt;User&gt; userList = new ArrayList<>(); // 维护用户列表

    @Override
    public void registerUser(User user) {
        if (!userList.contains(user)) {
            userList.add(user);
            System.out.println("用户 " + user.getUsername() + " 加入聊天");
        }
    }

    @Override
    public void sendMessage(String message, User sender, User receiver) {
        if (userList.contains(sender) && userList.contains(receiver)) {
            receiver.receiveMessage(message, sender);
        } else {
            throw new RuntimeException("发送者或接收者未加入聊天");
        }
    }

    @Override
    public void sendGroupMessage(String message, User sender) {
        if (userList.contains(sender)) {
            // 转发给除发送者外的所有用户
            for (User user : userList) {
                if (!user.equals(sender)) {
                    user.receiveMessage(message, sender);
                }
            }
        } else {
            throw new RuntimeException("发送者未加入聊天");
        }
    }
}

// 客户端使用
public class MediatorClient {
    public static void main(String[] args) {
        // 创建中介者
        ChatMediator mediator = new ChatMediatorImpl();

        // 创建用户(自动注册到中介者)
        User user1 = new User("张三", mediator);
        User user2 = new User("李四", mediator);
        User user3 = new User("王五", mediator);

        // 一对一聊天
        System.out.println("\n--- 一对一聊天 ---");
        user1.sendTo("你好,李四", user2);

        // 群聊
        System.out.println("\n--- 群聊 ---");
        user3.sendGroup("大家好,我是王五");
    }
}

优缺点&场景:优点是减少对象间耦合、集中管理交互逻辑、扩展灵活;缺点是中介者可能成为全能类,逻辑复杂。适合纯Java中多对象交互频繁、耦合紧密的场景(聊天系统、组件通信、分布式服务协调)。

10. 解释器模式

核心逻辑:定义一种语言的语法规则,构建解释器来解释该语言中的表达式,将语法解析与执行分离,支持自定义语法规则的解析与执行。

暂时无法在豆包文档外展示此内容

Java实战案例:后端简单运算表达式解析场景,支持“加法+减法”运算语法,通过解释器解析表达式字符串(如“10+20-5”),计算结果,构建表达式树处理复杂语法。

// 上下文:存储表达式中的变量/值,传递解析状态
public class ExpressionContext {
    private Map<String, Integer&gt; valueMap = new HashMap<>();

    // 设置变量值(如 a=10, b=20)
    public void setValue(String key, int value) {
        valueMap.put(key, value);
    }

    // 获取变量值
    public int getValue(String key) {
        return valueMap.get(key);
    }
}

// 抽象表达式
public abstract class AbstractExpression {
    public abstract int interpret(ExpressionContext context);
}

// 终结符表达式:变量表达式(解析变量值)
public class VariableExpression extends AbstractExpression {
    private String variable;

    public VariableExpression(String variable) {
        this.variable = variable;
    }

    @Override
    public int interpret(ExpressionContext context) {
        return context.getValue(variable); // 从上下文获取变量值
    }
}

// 终结符表达式:常量表达式(解析常量值)
public class ConstantExpression extends AbstractExpression {
    private int value;

    public ConstantExpression(int value) {
        this.value = value;
    }

    @Override
    public int interpret(ExpressionContext context) {
        return value; // 常量值直接返回
    }
}

// 非终结符表达式:加法表达式
public class AddExpression extends AbstractExpression {
    private AbstractExpression left; // 左表达式
    private AbstractExpression right; // 右表达式

    public AddExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(ExpressionContext context) {
        // 解释左右表达式并相加
        return left.interpret(context) + right.interpret(context);
    }
}

// 非终结符表达式:减法表达式
public class SubtractExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public SubtractExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(ExpressionContext context) {
        return left.interpret(context) - right.interpret(context);
    }
}

// 客户端使用:构建表达式树并解析
public class InterpreterClient {
    public static void main(String[] args) {
        // 构建表达式:a + b - 5(a=10, b=20)
        ExpressionContext context = new ExpressionContext();
        context.setValue("a", 10);
        context.setValue("b", 20);

        // 构建表达式树
        AbstractExpression a = new VariableExpression("a");
        AbstractExpression b = new VariableExpression("b");
        AbstractExpression constant = new ConstantExpression(5);
        AbstractExpression add = new AddExpression(a, b);
        AbstractExpression subtract = new SubtractExpression(add, constant);

        // 解析表达式并计算结果
        int result = subtract.interpret(context);
        System.out.println("表达式 a + b - 5 的结果:" + result);
    }
}

优缺点&场景:优点是语法规则可扩展、解析逻辑清晰;缺点是语法复杂时表达式树庞大,效率低、维护难。适合纯Java中简单语法解析、自定义规则场景(表达式计算、配置解析、简单脚本解释)。

11. 访问者模式

核心逻辑:定义一个访问者对象,封装对元素对象的操作,元素对象接受访问者访问,使操作逻辑与元素本身分离,支持动态扩展对元素的操作。

暂时无法在豆包文档外展示此内容

Java实战案例:后端数据统计场景,元素为“订单”“商品”,访问者为“金额统计访问者”“数量统计访问者”,通过访问者动态扩展统计逻辑,不修改元素类。

// 访问者接口
public interface DataVisitor {
    void visit(OrderElement order); // 访问订单元素
    void visit(ProductElement product); // 访问商品元素
}

// 元素接口
public interface DataElement {
    void accept(DataVisitor visitor); // 接受访问者访问
}

// 具体元素1:订单元素
public class OrderElement implements DataElement {
    private String orderNo;
    private double amount; // 订单金额

    public OrderElement(String orderNo, double amount) {
        this.orderNo = orderNo;
        this.amount = amount;
    }

    @Override
    public void accept(DataVisitor visitor) {
        visitor.visit(this); // 接受访问者,调用对应访问方法
    }

    // getter
    public String getOrderNo() {
        return orderNo;
    }

    public double getAmount() {
        return amount;
    }
}

// 具体元素2:商品元素
public class ProductElement implements DataElement {
    private String productId;
    private int count; // 商品数量

    public ProductElement(String productId, int count) {
        this.productId = productId;
        this.count = count;
    }

    @Override
    public void accept(DataVisitor visitor) {
        visitor.visit(this);
    }

    // getter
    public String getProductId() {
        return productId;
    }

    public int getCount() {
        return count;
    }
}

// 具体访问者1:金额统计访问者
public class AmountStatVisitor implements DataVisitor {
    private double totalAmount = 0;

    @Override
    public void visit(OrderElement order) {
        totalAmount += order.getAmount(); // 累加订单金额
    }

    @Override
    public void visit(ProductElement product) {
        // 商品元素不参与金额统计,空实现
    }

    // 获取总金额
    public double getTotalAmount() {
        return totalAmount;
    }
}

// 具体访问者2:数量统计访问者
public class CountStatVisitor implements DataVisitor {
    private int totalCount = 0;

    @Override
    public void visit(OrderElement order) {
        // 订单元素不参与数量统计,空实现
    }

    @Override
    public void visit(ProductElement product) {
        totalCount += product.getCount(); // 累加商品数量
    }

    // 获取总数量
    public int getTotalCount() {
        return totalCount;
    }
}

// 对象结构:管理元素集合
public class DataStructure {
    private List<DataElement> elements = new ArrayList<>();

    // 添加元素
    public void addElement(DataElement element) {
        elements.add(element);
    }

    // 遍历所有元素,接受访问者访问
    public void acceptVisitor(DataVisitor visitor) {
        for (DataElement element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端使用
public class VisitorClient {
    public static void main(String[] args) {
        // 初始化对象结构并添加元素
        DataStructure dataStructure = new DataStructure();
        dataStructure.addElement(new OrderElement("ORDER006", 299.9));
        dataStructure.addElement(new OrderElement("ORDER007", 599.9));
        dataStructure.addElement(new ProductElement("PROD001", 10));
        dataStructure.addElement(new ProductElement("PROD002", 20));

        // 金额统计
        AmountStatVisitor amountVisitor = new AmountStatVisitor();
        dataStructure.acceptVisitor(amountVisitor);
        System.out.println("订单总金额:" + amountVisitor.getTotalAmount() + "元");

        // 数量统计
        CountStatVisitor countVisitor = new CountStatVisitor();
        dataStructure.acceptVisitor(countVisitor);
        System.out.println("商品总数量:" + countVisitor.getTotalCount() + "件");
    }
}

优缺点&场景:优点是分离操作与元素、扩展操作灵活、集中管理操作逻辑;缺点是元素类扩展困难(新增元素需修改访问者接口)。适合纯Java中元素稳定、操作多变的场景(数据统计、报表生成、复杂对象遍历操作)。

四、设计模式核心总结

23种设计模式按三大类分工明确:创建型聚焦“对象创建”,结构型聚焦“系统结构”,行为型聚焦“交互行为”,核心目标均为解耦、复用、可维护。实际开发中无需刻意套用,需结合场景选择——简单场景用工厂、单例,复杂对象用建造者、原型,多对象交互用观察者、中介者,状态多变用状态模式,操作扩展用访问者模式。面试中需掌握每种模式的核心逻辑、案例场景、优缺点,结合项目经验说明落地方式,重点理解“组合优于继承”“面向接口编程”等设计原则。