Java设计模式全解析:23种模式的理论与实践指南

设计模式是软件工程领域的经验结晶,掌握设计模式不仅是技术的提升,更是架构思维的飞跃。本文将系统性地解析Java 23种设计模式,从理论基础到实战应用,助你构建优雅、可维护的代码体系。

文章目录


设计模式分类与概述

设计模式根据其解决问题的不同类型,可分为三大类别:创建型结构型行为型。每类模式都有其独特的核心目标和典型应用场景。

创建型设计模式概述

核心目标:封装对象创建过程,实现对象实例化与使用逻辑的解耦。

创建型设计模式通过将对象实例化逻辑与使用逻辑解耦,提升系统的灵活性和可维护性。这种解耦机制使代码在面对需求变化时,能通过调整创建逻辑而非修改使用代码来适应变化,符合开闭原则。

五种核心创建型模式及其定位

模式名称 核心定位 典型应用场景
单例模式 确保类在系统中仅存在唯一实例 全局配置管理、日志对象、数据库连接池
工厂方法模式 定义创建对象的接口,由子类决定具体实现 数据库驱动选择、日志框架
抽象工厂模式 提供接口创建一系列相关对象 跨平台UI组件库、产品族创建
建造者模式 分离复杂对象的构建与表示 多参数POJO构建、文档生成器
原型模式 通过复制现有实例创建新对象 对象池化、复杂对象的快速复制

结构型设计模式概述

核心目标:优化类与对象组合关系,通过灵活组合方式实现功能复用与系统解耦。

结构型设计模式包含七种核心模式,每种模式针对特定的结构优化场景:

  • 适配器模式:解决接口不兼容问题
  • 装饰器模式:实现对象功能的动态扩展
  • 代理模式:控制对象访问,实现功能增强
  • 组合模式:构建树形结构,统一处理单个与组合对象
  • 桥接模式:分离抽象与实现,实现多维度独立扩展
  • 外观模式:简化复杂系统交互,提供统一入口
  • 享元模式:实现对象复用,降低内存占用

典型应用

  • Spring AOP框架通过代理模式实现横切关注点分离
  • UI组件库利用组合模式构建复杂界面树形结构

行为型设计模式概述

核心目标:规范对象间交互逻辑与职责分配,通过封装行为变化提升系统可维护性。

行为型设计模式涵盖11种经典模式,专注于解决复杂业务场景下的对象协作问题。

典型应用场景

  • 业务流程:责任链模式实现请求的分级处理
  • 状态管理:状态模式处理对象生命周期的状态转换
  • 事件驱动:观察者模式构建松耦合的通知机制

创建型设计模式详细解析

1. 单例模式

核心特点

  • 控制实例唯一性,确保类在系统中只存在一个实例
  • 支持延迟初始化或饿汉式初始化
  • 提供全局访问点,便于系统统一调用

UML类图描述

复制代码
Singleton
├── - instance: Singleton (静态私有)
├── - Singleton() (私有构造)
└── + getInstance(): Singleton (静态公有方法)

适用场景

  • 资源共享场景:数据库连接池、线程池
  • 配置管理场景:系统参数配置类、环境配置中心
  • 日志管理场景:日志记录器、异常追踪器

优缺点分析

优势 劣势
节省系统资源,避免重复创建 扩展性差,难以继承和修改
避免多实例导致的冲突问题 全局状态导致单元测试困难
提供全局统一的访问入口 违反单一职责原则

实际项目应用指南

选择依据

  • 需要全局唯一实例的场景
  • 需要频繁创建和销毁的对象
  • 资源密集型对象(如数据库连接)

使用技巧

java 复制代码
// 推荐:枚举式单例(线程安全,防反射攻击)
public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务逻辑
    }
}

// 双重检查锁定(DCL)
public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

常见误区

  • ❌ 忽略多线程环境下的线程安全问题
  • ❌ 序列化破坏单例(需重写readResolve()方法)
  • ❌ 反射攻击未防护(在构造器中添加校验)

2. 工厂方法模式

核心特点

  • 定义创建对象的接口,由子类决定实例化类型
  • 产品创建与使用解耦,符合开闭原则
  • 工厂接口标准化产品创建流程

UML类图描述

复制代码
           ┌─────────────────┐
           │  ProductFactory │ (抽象工厂)
           └────────┬────────┘
                    │ factoryMethod()
                    ↓
      ┌───────────────────────────┐
      │                           │
┌─────┴──────┐           ┌────────┴────────┐
│ Concrete   │           │ Concrete       │
│Factory1    │           │Factory2         │
└─────┬──────┘           └────────┬────────┘
      │                           │
      ↓                           ↓
┌─────────┐              ┌─────────┐
│Product1 │              │Product2 │
└─────────┘              └─────────┘

适用场景

  • 产品种类稳定但具体实现多变
  • 框架设计需要支持扩展
  • 数据库驱动、日志输出等多类型产品

优缺点分析

优势 劣势
符合开闭原则,扩展新产品无需修改代码 每新增一种产品需对应新增工厂类
产品创建与使用解耦 系统类数量增加,复杂度上升
  • 工厂类职责单一,便于维护 | 过度抽象可能导致设计复杂化 |

实际项目应用指南

选择依据

  • 需要动态决定创建哪种产品
  • 产品类型可能频繁扩展
  • 框架设计需要灵活的创建机制

使用技巧

java 复制代码
// 抽象产品
public interface Logger {
    void log(String message);
}

// 具体产品
public class ConsoleLogger implements Logger {
    public void log(String message) {
        System.out.println("[Console] " + message);
    }
}

public class FileLogger implements Logger {
    public void log(String message) {
        // 写入文件
    }
}

// 抽象工厂
public interface LoggerFactory {
    Logger createLogger();
}

// 具体工厂
public class ConsoleLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        LoggerFactory factory = new ConsoleLoggerFactory();
        Logger logger = factory.createLogger();
        logger.log("Hello World!");
    }
}

常见误区

  • ❌ 工厂类职责过重,添加业务逻辑
  • ❌ 简单场景过度抽象
  • ❌ 未使用依赖注入管理工厂生命周期

3. 抽象工厂模式

核心特点

  • 创建产品族,确保产品族内的一致性
  • 接口隔离,分离不同产品族的创建逻辑
  • 支持多产品族的协同工作

UML类图描述

复制代码
          ┌─────────────────┐
          │ AbstractFactory │
          └────────┬────────┘
                   │
       ┌───────────┼───────────┐
       ↓           ↓           ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│createA() │ │createB() │ │createC() │
└──────────┘ └──────────┘ └──────────┘

适用场景

  • 需要多个产品族且族内产品需协同工作
  • 跨平台UI组件库(Windows/macOS风格)
  • 多数据库访问层设计

优缺点分析

优势 劣势
确保产品族内的一致性 新增产品族需修改抽象工厂接口
隔离具体实现细节 系统抽象度高,理解难度大
支持产品族的整体切换 扩展困难,违反开闭原则

实际项目应用指南

选择依据

  • 产品数量多且分成多个族
  • 需要保证同族产品的一致性
  • 系统需要支持多套产品体系

使用技巧

java 复制代码
// 抽象产品族
public interface Button {
    void render();
}

public interface TextBox {
    void render();
}

// Windows产品族
public class WindowsButton implements Button {
    public void render() {
        System.out.println("渲染Windows风格按钮");
    }
}

public class WindowsTextBox implements TextBox {
    public void render() {
        System.out.println("渲染Windows风格文本框");
    }
}

// macOS产品族
public class MacButton implements Button {
    public void render() {
        System.out.println("渲染Mac风格按钮");
    }
}

// 抽象工厂
public interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}

// Windows工厂
public class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }
    
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}

常见误区

  • ❌ 产品族结构不稳定时使用
  • ❌ 单一产品场景误用抽象工厂
  • ❌ 工厂接口过于庞大

4. 建造者模式

核心特点

  • 分步构建复杂对象,将创建过程分解为独立步骤
  • 隔离构建过程与表示,相同流程可生成不同产品
  • 指挥者控制构建流程,统一调度建造步骤

UML类图描述

复制代码
    ┌───────────┐
    │  Director │ (指挥者)
    └─────┬─────┘
          │
    ┌─────┴─────┐
    │ Builder   │ (抽象建造者)
    └─────┬─────┘
          │
    ┌─────┴──────────┐
    ↓                 ↓
┌─────────┐     ┌─────────┐
│Concrete │     │ Product │
│Builder  │     │         │
└─────────┘     └─────────┘

适用场景

  • 对象属性多且构建逻辑复杂
  • 多参数POJO构建,避免构造器膨胀
  • 文档生成器(HTML/Markdown文档分步构建)

优缺点分析

优势 劣势
构建过程清晰可控 类数量增加,需定义多个建造者
  • 灵活切换产品表示 | 构建逻辑分散,步骤分布在不同类中 |
    | 支持构建步骤的灵活组合 | 适用场景相对有限 |

实际项目应用指南

选择依据

  • 对象有多个可选参数
  • 创建过程复杂,需要分步骤
  • 不同构建过程需要创建不同表示

使用技巧

java 复制代码
// 产品类
public class Computer {
    private String cpu;
    private String ram;
    private String storage;
    
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
    }
    
    public static class Builder {
        private String cpu = "Intel i5";
        private String ram = "8GB";
        private String storage = "256GB SSD";
        
        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        
        public Builder ram(String ram) {
            this.ram = ram;
            return this;
        }
        
        public Builder storage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer.Builder()
            .cpu("Intel i7")
            .ram("16GB")
            .storage("1TB SSD")
            .build();
    }
}

常见误区

  • ❌ 与工厂模式混淆(建造者聚焦分步构建,工厂侧重类型选择)
  • ❌ 简单对象滥用建造者模式
  • ❌ 建造者类包含业务逻辑

5. 原型模式

核心特点

  • 避免直接使用构造函数,通过克隆方法生成对象副本
  • 支持深拷贝与浅拷贝的灵活控制
  • 高效创建对象,避免重复初始化开销

UML类图描述

复制代码
   ┌─────────────┐
   │ Prototype   │ (抽象原型)
   ├─────────────┤
   │ + clone()   │
   └─────┬───────┘
         │
    ┌────┴────┐
    ↓         ↓
┌─────────┐ ┌─────────┐
│Concrete │ │Concrete │
│Prototype│ │Prototype│
└─────────┘ └─────────┘

适用场景

  • 对象创建成本高(数据库连接、复杂初始化)
  • 需要动态生成大量相似对象(游戏角色、对象池管理)
  • 需保留对象状态快照进行恢复操作

优缺点分析

优势 劣势
性能优化,避免重复初始化开销 深拷贝实现复杂,需处理嵌套对象引用
简化创建过程,无需关注构造细节 可能违反单一职责原则
支持对象状态的保存与恢复 Cloneable接口仅作为标记,无实际方法

实际项目应用指南

选择依据

  • 对象初始化耗时较长
  • 需要大量相似对象
  • 需要保存对象状态快照

使用技巧

java 复制代码
// 实现Cloneable接口
public class Sheep implements Cloneable {
    private String name;
    private int age;
    
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 浅拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    // 深拷贝实现
    @Override
    protected Object deepClone() throws CloneNotSupportedException {
        Sheep sheep = (Sheep) super.clone();
        // 处理引用类型的深拷贝
        return sheep;
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep original = new Sheep("多利", 2);
        Sheep cloned = (Sheep) original.clone();
    }
}

常见误区

  • ❌ 未区分浅拷贝与深拷贝
  • ❌ 忽略嵌套对象的引用问题
  • ❌ 序列化方式实现深拷贝时忘记实现Serializable

结构型设计模式详细解析

6. 适配器模式

核心特点

  • 转换接口,解决接口不兼容问题
  • 兼容性处理,使现有类能够复用
  • 透明复用适配者功能

UML类图描述

复制代码
┌───────────┐          ┌─────────────┐
│  Client   │─────────►│ Target      │
└───────────┘          └──────┬──────┘
                              │
                      ┌───────┴────────┐
                      │ Adapter        │
                      └───────┬────────┘
                              │
                      ┌───────┴────────┐
                      │ Adaptee        │
                      │ (现有不兼容类) │
                      └────────────────┘

适用场景

  • 接口不兼容的系统集成
  • 第三方库适配(将外部API转换为系统内部接口)
  • 旧系统升级(保留legacy代码功能对接新接口)

优缺点分析

优势 劣势
实现现有代码复用 增加系统复杂度
促进系统解耦 过多适配器导致维护困难
灵活性好,可以透明复用 需要额外的适配器类

实际项目应用指南

选择依据

  • 需要使用现有类但其接口不满足需求
  • 两个类所做的事情相同但接口不同
  • 需要集成第三方库或遗留系统

使用技巧

java 复制代码
// 目标接口
public interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配的类(现有不兼容接口)
public class AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("播放VLC文件: " + fileName);
    }
    
    public void playMp4(String fileName) {
        System.out.println("播放MP4文件: " + fileName);
    }
}

// 适配器类
public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMusicPlayer;
    
    public MediaAdapter() {
        advancedMusicPlayer = new AdvancedMediaPlayer();
    }
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

常见误区

  • ❌ 类适配器与对象适配器混淆(推荐使用对象适配器降低耦合)
  • ❌ 适配器职责过重,承担过多业务逻辑
  • ❌ 过度使用适配器导致系统复杂度上升

7. 桥接模式

核心特点

  • 分离抽象与实现,通过组合而非继承
  • 独立扩展两个维度
  • 符合开闭原则,可独立扩展任一维度

UML类图描述

复制代码
       ┌──────────┐
       │ Abstraction│ (抽象化)
       └────┬─────┘
            │ implements
       ┌────┴─────┐
       ↓          │
┌───────────┐    │
│ Refined   │────┼────► ┌─────────────┐
│Abstraction│    │      │Implementor  │
└───────────┘    │      └──────┬──────┘
                 │             │
       ┌─────────┴────────┐    ↓
       ↓                  ↓┌────────────┐
┌──────────┐      ┌──────────┤Concrete   │
│Concrete  │      │Concrete  │Implementor│
│Implemento│      │Abstraction│          │
└──────────┘      └──────────┘└────────────┘

适用场景

  • 多维度变化且需独立扩展
  • 图形界面中形状与颜色的组合
  • 消息系统中消息类型与传输方式的搭配

优缺点分析

优势 劣势
扩展性好,独立扩展两个维度 系统抽象度高,理解难度大
符合开闭原则 需要正确识别抽象和实现维度
减少子类数量 设计复杂度增加

实际项目应用指南

选择依据

  • 存在两个或多个独立变化的维度
  • 需要独立扩展抽象和实现
  • 避免继承导致的类爆炸

使用技巧

java 复制代码
// 实现接口(颜色维度)
public interface Color {
    void applyColor();
}

public class Red implements Color {
    public void applyColor() {
        System.out.println("应用红色");
    }
}

public class Blue implements Color {
    public void applyColor() {
        System.out.println("应用蓝色");
    }
}

// 抽象类(形状维度)
public abstract class Shape {
    protected Color color;
    
    public Shape(Color color) {
        this.color = color;
    }
    
    public abstract void draw();
}

public class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }
    
    @Override
    public void draw() {
        System.out.print("圆形 - ");
        color.applyColor();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Shape redCircle = new Circle(new Red());
        redCircle.draw();  // 输出:圆形 - 应用红色
    }
}

常见误区

  • ❌ 单一维度变化场景使用
  • ❌ 抽象层与实现层未真正解耦
  • ❌ 未能正确识别独立变化的维度

8. 组合模式

核心特点

  • 树形结构表示部分-整体关系
  • 统一对待单个对象与组合对象
  • 支持递归组合操作

UML类图描述

复制代码
       ┌─────────────┐
       │ Component   │ (抽象构件)
       ├─────────────┤
       │ + operation()│
       │ + add()      │
       │ + remove()   │
       └─────┬───────┘
             │
      ┌──────┴──────┐
      ↓             ↓
┌─────────┐  ┌──────────┐
│ Leaf    │  │Composite │ (容器构件)
└─────────┘  ├──────────┤
             │ + add()   │
             │ + remove()│
             └────┬─────┘
                  │
                  └────► Component

适用场景

  • 树形结构数据(文件系统、UI组件树)
  • 组织架构(部门与员工)
  • 需要统一处理单个对象与组合对象

优缺点分析

优势 劣势
简化客户端代码,无需区分处理 设计复杂度较高
易于扩展新构件类型 限制容器中的构件类型时需额外判断
支持递归操作,层次清晰 过度通用化可能违背单一职责

实际项目应用指南

选择依据

  • 存在树形结构或部分-整体层次关系
  • 需要统一处理单个对象和组合对象
  • 客户端代码需要忽略组合对象与单个对象的差异

使用技巧

java 复制代码
// 抽象构件
public abstract class FileSystemComponent {
    protected String name;
    
    public FileSystemComponent(String name) {
        this.name = name;
    }
    
    public abstract void display();
}

// 叶子构件(文件)
public class File extends FileSystemComponent {
    public File(String name) {
        super(name);
    }
    
    @Override
    public void display() {
        System.out.println("文件: " + name);
    }
}

// 容器构件(文件夹)
public class Folder extends FileSystemComponent {
    private List<FileSystemComponent> children = new ArrayList<>();
    
    public Folder(String name) {
        super(name);
    }
    
    public void add(FileSystemComponent component) {
        children.add(component);
    }
    
    public void remove(FileSystemComponent component) {
        children.remove(component);
    }
    
    @Override
    public void display() {
        System.out.println("文件夹: " + name);
        for (FileSystemComponent component : children) {
            component.display();
        }
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Folder root = new Folder("根目录");
        File file1 = new File("文件1.txt");
        File file2 = new File("文件2.txt");
        
        root.add(file1);
        root.add(file2);
        root.display();
    }
}

常见误区

  • ❌ 叶子节点实现add/remove方法(应抛出UnsupportedOperationException)
  • ❌ 树形结构过深导致性能问题
  • ❌ 未选择合适的组合模式(透明组合 vs 安全组合)

9. 装饰器模式

核心特点

  • 动态扩展对象功能,无需修改原有类
  • 通过组合替代继承,避免类爆炸
  • 透明包裹对象,对客户端透明

UML类图描述

复制代码
       ┌─────────────┐
       │ Component   │ (抽象构件)
       ├─────────────┤
       │ + operation()│
       └─────┬───────┘
             │
      ┌──────┴──────┐
      ↓             ↓
┌─────────┐  ┌──────────────┐
│Concrete │  │Decorator     │
│Component│  └──────┬───────┘
└─────────┘         │
            ┌───────┴───────┐
            ↓               ↓
    ┌────────────┐  ┌────────────┐
    │ Concrete   │  │ Concrete   │
    │ Decorator  │  │ Decorator  │
    └────────────┘  └────────────┘

适用场景

  • I/O流包装、日志功能增强
  • 权限控制、缓存管理
  • 需动态添加或移除功能的场景

优缺点分析

优势 劣势
功能扩展灵活,运行时动态添加 多层装饰导致调试困难
避免类爆炸,通过组合替代继承 增加代码复杂度与理解成本
符合开闭原则 装饰顺序影响功能执行

实际项目应用指南

选择依据

  • 需要动态扩展对象功能
  • 不能使用继承来扩展功能
  • 需要为对象添加多个可选功能

使用技巧

java 复制代码
// 抽象构件
public interface Coffee {
    double cost();
    String description();
}

// 具体构件
public class SimpleCoffee implements Coffee {
    public double cost() {
        return 1.0;
    }
    
    public String description() {
        return "简单咖啡";
    }
}

// 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    public double cost() {
        return decoratedCoffee.cost();
    }
    
    public String description() {
        return decoratedCoffee.description();
    }
}

// 具体装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double cost() {
        return super.cost() + 0.5;
    }
    
    @Override
    public String description() {
        return super.description() + ", 加牛奶";
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        coffee = new MilkDecorator(coffee);
        coffee = new MilkDecorator(coffee); // 加双倍牛奶
        
        System.out.println(coffee.description());
        System.out.println("价格: $" + coffee.cost());
    }
}

常见误区

  • ❌ 与继承混淆(装饰器使用组合)
  • ❌ 装饰链过长导致调试困难
  • ❌ 装饰器添加新方法破坏透明性

10. 外观模式

核心特点

  • 简化子系统接口,提供统一访问入口
  • 封装子系统复杂性,隐藏内部实现
  • 实现客户端与子系统解耦

UML类图描述

复制代码
    ┌──────────┐
    │  Client  │
    └────┬─────┘
         │
    ┌────┴────────┐
    │ Facade      │ (外观)
    └────┬────────┘
         │
    ┌────┼────────┐
    ↓    ↓        ↓
┌─────┐┌────┐ ┌──────┐
│SubA ││SubB│ │ SubC │
└─────┘└────┘ └──────┘

适用场景

  • 复杂系统的简化访问
  • 第三方API封装(如支付SDK统一接口)
  • 框架入口类(如Spring的ApplicationContext)

优缺点分析

优势 劣势
降低使用难度,简化客户端代码 外观类可能成为性能瓶颈
提高系统安全性,隐藏内部实现 过度封装会限制子系统灵活使用
降低客户端与子系统的耦合 外观类职责可能过重

实际项目应用指南

选择依据

  • 子系统复杂,客户端难以直接使用
  • 需要简化接口,降低学习成本
  • 需要隔离客户端与子系统的变化

使用技巧

java 复制代码
// 子系统A
public class SubsystemA {
    public void operationA() {
        System.out.println("子系统A的操作");
    }
}

// 子系统B
public class SubsystemB {
    public void operationB() {
        System.out.println("子系统B的操作");
    }
}

// 子系统C
public class SubsystemC {
    public void operationC() {
        System.out.println("子系统C的操作");
    }
}

// 外观类
public class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;
    private SubsystemC subsystemC;
    
    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
        subsystemC = new SubsystemC();
    }
    
    public void operation() {
        subsystemA.operationA();
        subsystemB.operationB();
        subsystemC.operationC();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation();
    }
}

常见误区

  • ❌ 外观类添加业务逻辑(仅负责协调)
  • ❌ 为满足特殊需求暴露子系统接口
  • ❌ 过度使用外观模式导致设计复杂化

11. 享元模式

核心特点

  • 共享细粒度对象,减少内存占用
  • 分离内部状态与外部状态
  • 通过享元工厂管理对象池

UML类图描述

复制代码
    ┌─────────────┐
    │ Flyweight   │ (抽象享元)
    ├─────────────┤
    │ + operation()│
    └─────┬───────┘
          │
    ┌─────┴────────┐
    ↓               ↓
┌─────────┐    ┌─────────────┐
│Concrete │    │Flyweight    │
│Flyweight│    │Factory      │
└─────────┘    └─────────────┘

适用场景

  • 大量相似对象导致内存占用过高
  • 文本编辑器的字符缓存
  • 游戏中的角色模型复用、数据库连接池管理

优缺点分析

优势 劣势
显著节省内存空间 设计复杂度增加
提升系统性能 外部状态管理成本上升
支持对象复用 需要正确识别内外部状态

实际项目应用指南

选择依据

  • 系统中存在大量相似对象
  • 对象的大部分状态可以外部化
  • 需要减少内存占用

使用技巧

java 复制代码
// 享元接口
public interface Flyweight {
    void operation(String extrinsicState);
}

// 具体享元
public class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;  // 内部状态
    
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    
    @Override
    public void operation(String extrinsicState) {
        System.out.println("内部状态: " + intrinsicState + 
                         ", 外部状态: " + extrinsicState);
    }
}

// 享元工厂
public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();
    
    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = flyweights.get(key);
        if (flyweight == null) {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweight;
    }
    
    public int getFlyweightCount() {
        return flyweights.size();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        
        Flyweight flyweight1 = factory.getFlyweight("共享状态A");
        flyweight1.operation("外部状态1");
        
        Flyweight flyweight2 = factory.getFlyweight("共享状态A");
        flyweight2.operation("外部状态2");
        
        System.out.println("享元对象数量: " + factory.getFlyweightCount());
    }
}

常见误区

  • ❌ 外部状态存储在享元对象中
  • ❌ 未正确识别内部状态与外部状态
  • ❌ 忽略线程安全问题

12. 代理模式

核心特点

  • 控制对象访问,作为中间层
  • 附加功能扩展(日志、缓存、权限)
  • 延迟加载机制

UML类图描述

复制代码
       ┌────────────┐
       │ Subject    │ (抽象主题)
       ├────────────┤
       │ + request()│
       └─────┬──────┘
             │
      ┌──────┴──────┐
      ↓             ↓
┌─────────┐  ┌─────────────┐
│ Real    │  │Proxy        │
│ Subject │  └──────┬──────┘
└─────────┘         │
                    │
                    ↓
                  RealSubject

适用场景

  • 访问控制(权限保护)
  • 远程服务调用的网络代理
  • 延迟加载(虚拟代理)
  • 智能引用(引用计数、缓存)

优缺点分析

优势 劣势
职责分离清晰(代理控制逻辑,真实对象业务逻辑) 代理层增加性能开销
功能增强灵活,可动态添加横切关注点 系统复杂度提升
保护真实对象,控制访问 过度代理增加调用链长度

实际项目应用指南

选择依据

  • 需要控制对对象的访问
  • 需要在访问对象时添加额外功能
  • 需要延迟加载对象

使用技巧

java 复制代码
// 抽象主题
public interface Subject {
    void request();
}

// 真实主题
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("处理真实业务逻辑");
    }
}

// 代理类
public class Proxy implements Subject {
    private RealSubject realSubject;
    
    @Override
    public void request() {
        // 前置处理
        System.out.println("权限检查");
        System.out.println("日志记录");
        
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        
        // 调用真实对象
        realSubject.request();
        
        // 后置处理
        System.out.println("缓存结果");
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

常见误区

  • ❌ 与装饰器模式混淆(代理侧重控制访问,装饰器侧重功能增强)
  • ❌ 过度设计代理层
  • ❌ 未考虑代理的性能开销

行为型设计模式详细解析

13. 责任链模式

核心特点

  • 请求沿链传递,每个处理者自主决定处理或转发
  • 动态组合责任,灵活配置处理链
  • 实现请求发送者与处理者的解耦

UML类图描述

复制代码
    ┌──────────────┐
    │ Handler      │ (抽象处理者)
    ├──────────────┤
    │ + handleRequest()│
    │ - next: Handler│
    └──────┬───────┘
           │
    ┌──────┴──────┐
    ↓             ↓
┌──────────┐ ┌──────────┐
│Concrete  │ │Concrete  │
│Handler1  │ │Handler2  │
└──────────┘ └──────────┘

适用场景

  • 多对象可处理同一请求且处理顺序可变
  • 表单验证中需依次校验不同字段
  • 日志系统按级别传递日志事件

优缺点分析

优势 劣势
实现请求发送者与处理者的解耦 请求未被处理的风险
系统灵活性高,可动态调整责任链 链过长导致性能损耗
简化对象间的交互关系 调试困难,请求流向不明确

实际项目应用指南

选择依据

  • 有多个对象可以处理请求,但不确定具体哪个
  • 需要动态指定处理对象集合
  • 需要按指定顺序处理请求

使用技巧

java 复制代码
// 抽象处理者
public abstract class Handler {
    protected Handler nextHandler;
    
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }
    
    public final void handleRequest(int level) {
        if (this.getHandlerLevel() == level) {
            this.echo();
        } else if (nextHandler != null) {
            nextHandler.handleRequest(level);
        } else {
            System.out.println("没有处理者处理该请求");
        }
    }
    
    protected abstract int getHandlerLevel();
    protected abstract void echo();
}

// 具体处理者
public class ConcreteHandler1 extends Handler {
    @Override
    protected int getHandlerLevel() {
        return 1;
    }
    
    @Override
    protected void echo() {
        System.out.println("处理者1处理请求");
    }
}

public class ConcreteHandler2 extends Handler {
    @Override
    protected int getHandlerLevel() {
        return 2;
    }
    
    @Override
    protected void echo() {
        System.out.println("处理者2处理请求");
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        
        handler1.setNext(handler2);
        
        handler1.handleRequest(1);  // 处理者1处理
        handler1.handleRequest(2);  // 处理者2处理
    }
}

常见误区

  • ❌ 未设置默认处理者导致请求未处理
  • ❌ 责任链过长导致性能问题
  • ❌ 处理者之间存在循环依赖

14. 命令模式

核心特点

  • 封装请求为对象,实现操作的参数化
  • 支持撤销/重做功能
  • 解耦命令发送者与接收者

UML类图描述

复制代码
    ┌─────────────┐          ┌──────────────┐
    │  Client     │----------→│  Receiver    │
    └─────────────┘          └──────────────┘
            │
    ┌───────┼───────┐
    ↓       ↓       ↓
┌────────┐┌────────┐┌────────┐
│Command ││Invoker ││Concrete│
│        ││        ││Command │
└────────┘└────────┘└────────┘

适用场景

  • 需记录操作历史、支持撤销
  • GUI按钮事件响应、任务调度系统
  • 事务管理框架

优缺点分析

优势 劣势
解耦发送者与接收者 增加系统类数量
支持命令组合形成宏操作 复杂命令逻辑提升维护难度
  • 支持撤销/重做 | 命令粒度难以把握 |
    | 便于扩展新命令类型 | |

实际项目应用指南

选择依据

  • 需要将调用者与接收者解耦
  • 需要支持撤销/重做操作
  • 需要记录操作历史

使用技巧

java 复制代码
// 命令接口
public interface Command {
    void execute();
    void undo();
}

// 接收者
public class Light {
    public void on() {
        System.out.println("灯打开");
    }
    
    public void off() {
        System.out.println("灯关闭");
    }
}

// 具体命令
public class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.on();
    }
    
    @Override
    public void undo() {
        light.off();
    }
}

// 调用者
public class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void buttonPressed() {
        command.execute();
    }
    
    public void undoButtonPressed() {
        command.undo();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOnCommand = new LightOnCommand(light);
        
        RemoteControl remote = new RemoteControl();
        remote.setCommand(lightOnCommand);
        
        remote.buttonPressed();   // 灯打开
        remote.undoButtonPressed(); // 灯关闭
    }
}

常见误区

  • ❌ 命令粒度过细或过粗
  • ❌ 忽略undo/redo的实现
  • ❌ 命令对象持有过多状态

15. 解释器模式

核心特点

  • 定义语法规则,提供解释执行机制
  • 递归结构处理复杂表达式
  • 适用于特定领域语言(DSL)实现

UML类图描述

复制代码
    ┌─────────────┐
    │Expression   │ (抽象表达式)
    ├─────────────┤
    │ + interpret()│
    └─────┬───────┘
          │
   ┌──────┴──────┐
   ↓             ↓
┌─────────┐  ┌──────────┐
│Terminal │  │Non-Terminal│
│Expression│ │Expression  │
└─────────┘  └──────────┘

适用场景

  • 简单语法规则的解析
  • 配置文件解析、数学表达式计算
  • SQL解析器、规则引擎

优缺点分析

优势 劣势
易于扩展语法规则 处理复杂语法时效率低下
  • 针对性强,高效解决特定领域问题 | 维护困难,递归解释导致性能瓶颈 |
    | 语法规则清晰易懂 | 仅适用于简单语法场景 |

实际项目应用指南

选择依据

  • 需要解析简单语法规则
  • 频繁变化的特定领域语言
  • 需要支持自定义表达式

使用技巧

java 复制代码
// 抽象表达式
public interface Expression {
    int interpret();
}

// 终结符表达式(数字)
public class NumberExpression implements Expression {
    private int number;
    
    public NumberExpression(int number) {
        this.number = number;
    }
    
    @Override
    public int interpret() {
        return number;
    }
}

// 非终结符表达式(加法)
public class AddExpression implements Expression {
    private Expression left;
    private Expression right;
    
    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        // 解析表达式: 5 + 3
        Expression five = new NumberExpression(5);
        Expression three = new NumberExpression(3);
        Expression add = new AddExpression(five, three);
        
        System.out.println("结果: " + add.interpret());  // 输出: 8
    }
}

常见误区

  • ❌ 用于复杂语法场景(建议使用ANTLR等专业工具)
  • ❌ 递归深度过大导致栈溢出
  • ❌ 未考虑语法错误处理

16. 迭代器模式

核心特点

  • 遍历聚合对象无需暴露内部结构
  • 统一遍历接口,实现对不同容器的一致访问
  • 支持多种遍历方式

UML类图描述

复制代码
    ┌─────────────┐
    │ Iterator    │ (抽象迭代器)
    ├─────────────┤
    │ + hasNext() │
    │ + next()    │
    └─────────────┘
            ↑
            │ implements
    ┌───────┴───────┐
    │ Concrete      │
    │ Iterator      │
    └───────────────┘
            │
            ↓
    ┌─────────────┐
    │ Aggregate   │ (聚合)
    ├─────────────┤
    │ + iterator()│
    └─────────────┘

适用场景

  • 需遍历不同聚合结构
  • Java集合框架中的Iterator接口
  • 自定义容器需提供标准化遍历能力

优缺点分析

优势 劣势
简化客户端遍历逻辑 增加类数量(每个聚合需对应迭代器)
  • 符合单一职责原则 | 遍历算法相对固定,难以动态修改 |
    | 数据存储与遍历行为分离 | 迭代期间集合修改可能引发异常 |

实际项目应用指南

选择依据

  • 需要遍历聚合对象
  • 需要提供多种遍历方式
  • 希望隐藏聚合对象的内部表示

使用技巧

java 复制代码
// 迭代器接口
public interface Iterator {
    boolean hasNext();
    Object next();
}

// 聚合接口
public interface Aggregate {
    Iterator createIterator();
}

// 具体聚合
public class ConcreteAggregate implements Aggregate {
    private List<Object> items = new ArrayList<>();
    
    public void add(Object item) {
        items.add(item);
    }
    
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(this);
    }
    
    public List<Object> getItems() {
        return items;
    }
}

// 具体迭代器
public class ConcreteIterator implements Iterator {
    private ConcreteAggregate aggregate;
    private int current = 0;
    
    public ConcreteIterator(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
    }
    
    @Override
    public boolean hasNext() {
        return current < aggregate.getItems().size();
    }
    
    @Override
    public Object next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return aggregate.getItems().get(current++);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        ConcreteAggregate aggregate = new ConcreteAggregate();
        aggregate.add("项目1");
        aggregate.add("项目2");
        aggregate.add("项目3");
        
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

常见误区

  • ❌ 迭代器过度依赖具体聚合类
  • ❌ 未正确实现remove()方法
  • ❌ 忽略fail-fast机制

17. 中介者模式

核心特点

  • 集中管理对象间交互,减少直接耦合
  • 将多对多交互转化为一对多关系
  • 简化维护复杂度

UML类图描述

复制代码
        ┌─────────┐
        │ Mediator│
        └────┬────┘
             │
      ┌──────┼──────┐
      ↓      ↓      ↓
┌────────┐┌────────┐┌────────┐
│Colleague││Colleague││Colleague│
│  A     ││  B     ││  C     │
└────────┘└────────┘└────────┘

适用场景

  • 对象间交互复杂的多对多场景
  • 聊天室系统(用户通过服务器中转消息)
  • GUI组件协调(按钮与文本框通过表单中介联动)

优缺点分析

优势 劣势
降低耦合度,集中控制交互逻辑 中介者可能成为性能瓶颈
简化对象间关系 过度集中化导致中介者复杂度激增
  • 提高可维护性 | 中介者职责过重违背单一职责原则 |

实际项目应用指南

选择依据

  • 对象间存在复杂的多对多交互
  • 需要集中控制交互逻辑
  • 希望降低对象间的耦合度

使用技巧

java 复制代码
// 中介者接口
public interface Mediator {
    void sendMessage(Colleague colleague, String message);
}

// 同事抽象类
public abstract class Colleague {
    protected Mediator mediator;
    
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    
    public abstract void receiveMessage(String message);
    public abstract void sendMessage(String message);
}

// 具体同事
public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }
    
    @Override
    public void receiveMessage(String message) {
        System.out.println("同事A收到消息: " + message);
    }
    
    @Override
    public void sendMessage(String message) {
        System.out.println("同事A发送消息: " + message);
        mediator.sendMessage(this, message);
    }
}

// 具体中介者
public class ConcreteMediator implements Mediator {
    private ConcreteColleagueA colleagueA;
    private ConcreteColleagueB colleagueB;
    
    public void setColleagueA(ConcreteColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }
    
    public void setColleagueB(ConcreteColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }
    
    @Override
    public void sendMessage(Colleague colleague, String message) {
        if (colleague == colleagueA) {
            colleagueB.receiveMessage(message);
        } else {
            colleagueA.receiveMessage(message);
        }
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
        ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
        
        mediator.setColleagueA(colleagueA);
        mediator.setColleagueB(colleagueB);
        
        colleagueA.sendMessage("你好,同事B");
        colleagueB.sendMessage("你好,同事A");
    }
}

常见误区

  • ❌ 中介者职责过重
  • ❌ 同事对象直接持有具体中介者实例
  • ❅ 未按功能拆分多个中介者

18. 备忘录模式

核心特点

  • 保存对象内部状态,不破坏封装性
  • 支持状态恢复
  • 由原发器、备忘录、负责人三角色协作

UML类图描述

复制代码
    ┌──────────┐
    │ Originator│
    └────┬─────┘
         │ creates/uses
    ┌────┴────────┐
    ↓             ↓
┌─────────┐  ┌──────────┐
│Memento  │  │ Caretaker│
└─────────┘  └──────────┘

适用场景

  • 需要保存/恢复状态
  • 文本编辑器的撤销功能
  • 游戏进度存档系统
  • 配置项版本管理

优缺点分析

优势 劣势
状态管理逻辑清晰 频繁创建备忘录导致资源消耗
有效保护对象封装性 复杂对象状态复制产生性能成本
  • 支持多版本状态管理 | 需合理控制备忘录数量 |

实际项目应用指南

选择依据

  • 需要保存对象的历史状态
  • 需要实现撤销/重做功能
  • 需要对象状态的快照机制

使用技巧

java 复制代码
// 备忘录类
public class Memento {
    private String state;
    
    public Memento(String state) {
        this.state = state;
    }
    
    public String getState() {
        return state;
    }
}

// 原发器
public class Originator {
    private String state;
    
    public void setState(String state) {
        this.state = state;
        System.out.println("当前状态: " + state);
    }
    
    public String getState() {
        return state;
    }
    
    public Memento saveStateToMemento() {
        return new Memento(state);
    }
    
    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// 负责人
public class Caretaker {
    private List<Memento> mementoList = new ArrayList<>();
    
    public void add(Memento state) {
        mementoList.add(state);
    }
    
    public Memento get(int index) {
        return mementoList.get(index);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        
        originator.setState("状态1");
        caretaker.add(originator.saveStateToMemento());
        
        originator.setState("状态2");
        caretaker.add(originator.saveStateToMemento());
        
        originator.setState("状态3");
        
        // 恢复状态
        originator.getStateFromMemento(caretaker.get(0));
        System.out.println("恢复后的状态: " + originator.getState());
    }
}

常见误区

  • ❌ 备忘录类暴露内部状态字段
  • ❌ 未控制备忘录数量导致内存占用过高
  • ❌ 忽略深拷贝问题

19. 观察者模式

核心特点

  • 建立一对多的依赖关系
  • 状态变化自动通知所有观察者
  • 实现对象间的松耦合通信

UML类图描述

复制代码
    ┌───────────┐
    │  Subject  │ (主题)
    ├───────────┤
    │ + attach()│
    │ + detach()│
    │ + notify()│
    └───────────┘
            ↑
            │
    ┌───────┼───────┐
    ↓       ↓       ↓
┌────────┐┌────────┐┌────────┐
│Observer││Observer││Observer│
│   A    ││   B    ││   C    │
└────────┘└────────┘└────────┘

适用场景

  • 事件驱动场景(GUI按钮点击事件监听)
  • 消息队列的订阅发布机制
  • 分布式系统的数据同步

优缺点分析

优势 劣势
状态变化响应及时 通知顺序不确定
观察者扩展灵活 循环依赖可能导致死锁
  • 松耦合设计 | 观察者数量多时性能问题 |

实际项目应用指南

选择依据

  • 对象间存在一对多依赖关系
  • 一个对象的状态变化需要通知其他对象
  • 需要构建松耦合的事件驱动系统

使用技巧

java 复制代码
// 观察者接口
public interface Observer {
    void update(String message);
}

// 主题接口
public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// 具体主题
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;
    
    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
    
    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }
}

// 具体观察者
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);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        
        ConcreteObserver observer1 = new ConcreteObserver("观察者1");
        ConcreteObserver observer2 = new ConcreteObserver("观察者2");
        
        subject.attach(observer1);
        subject.attach(observer2);
        
        subject.setState("状态已更新");
    }
}

常见误区

  • ❌ 观察者未注销导致内存泄漏
  • ❌ 通知顺序不明确
  • ❅ 多线程环境下未考虑线程安全

20. 状态模式

核心特点

  • 封装状态行为,替代复杂条件判断
  • 状态转换由状态对象控制
  • 对象状态改变时行为随之改变

UML类图描述

复制代码
    ┌──────────┐
    │  Context │ (环境类)
    └────┬─────┘
         │ uses
    ┌────┴────────┐
    ↓             ↓
┌─────────┐  ┌─────────┐
│  State  │  │ Concrete│
│ (抽象)  │  │State A  │
└─────────┘  └─────────┘
             ↑
             │
    ┌────────┴────────┐
    ↓                 ↓
┌──────────┐    ┌──────────┐
│Concrete  │    │Concrete  │
│State B   │    │State C   │
└──────────┘    └──────────┘

适用场景

  • 对象状态多且转换复杂
  • 电商订单状态流转(待支付→已支付→已发货→已完成)
  • 工作流引擎中的任务状态管理

优缺点分析

优势 劣势
状态逻辑清晰,易于维护 状态类数量多
符合开闭原则,扩展方便 状态转换逻辑分散
避免复杂条件判断 理解成本增加

实际项目应用指南

选择依据

  • 对象行为随状态变化而变化
  • 状态转换规则复杂
  • 需要大量条件判断来描述对象状态

使用技巧

java 复制代码
// 抽象状态
public interface State {
    void handle(Context context);
}

// 具体状态A
public class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态: A");
        context.setState(new ConcreteStateB());
    }
}

// 具体状态B
public class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态: B");
        context.setState(new ConcreteStateA());
    }
}

// 环境类
public class Context {
    private State state;
    
    public Context(State state) {
        this.state = state;
    }
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        
        context.request();  // 当前状态: A
        context.request();  // 当前状态: B
        context.request();  // 当前状态: A
    }
}

常见误区

  • ❌ 状态类承担过多职责
  • ❌ 状态转换逻辑分散
  • ❅ 未使用集中式状态管理器

21. 策略模式

核心特点

  • 封装算法族,实现算法与使用分离
  • 支持运行时动态切换算法
  • 消除复杂条件判断

UML类图描述

复制代码
    ┌───────────┐
    │ Strategy  │ (抽象策略)
    ├───────────┤
    │ + execute()│
    └─────┬─────┘
          │
    ┌─────┴────────┐
    ↓              ↓
┌──────────┐  ┌──────────┐
│Concrete  │  │Concrete  │
│StrategyA │  │StrategyB │
└──────────┘  └──────────┘
        ↑           ↑
        └─────┬─────┘
              │
       ┌──────┴──────┐
       │   Context   │
       └─────────────┘

适用场景

  • 多种算法可选且需动态切换
  • 支付系统中不同支付方式的选择
  • 搜索引擎中多种排序算法的切换

优缺点分析

优势 劣势
算法切换灵活 客户端需了解所有策略
符合开闭原则 策略过多导致类膨胀
  • 算法独立变化 | 策略选择逻辑复杂 |

实际项目应用指南

选择依据

  • 系统中有多种同类算法可以互换
  • 算法需要动态切换
  • 需要隐藏具体算法实现细节

使用技巧

java 复制代码
// 策略接口
public interface Strategy {
    int execute(int a, int b);
}

// 具体策略A:加法
public class ConcreteStrategyAdd implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a + b;
    }
}

// 具体策略B:减法
public class ConcreteStrategySubtract implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a - b;
    }
}

// 上下文
public class Context {
    private Strategy strategy;
    
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyAdd());
        System.out.println("加法结果: " + context.executeStrategy(10, 5));  // 15
        
        context.setStrategy(new ConcreteStrategySubtract());
        System.out.println("减法结果: " + context.executeStrategy(10, 5));  // 5
    }
}

常见误区

  • ❌ 客户端直接依赖具体策略类
  • ❅ 策略选择逻辑复杂
  • ❌ 未结合工厂模式管理策略

22. 模板方法模式

核心特点

  • 定义算法骨架,延迟具体步骤到子类
  • 固定流程,灵活实现
  • 通过抽象类控制子类行为

UML类图描述

复制代码
    ┌──────────────────┐
    │AbstractClass     │ (抽象类)
    ├──────────────────┤
    │ + templateMethod()│
    │ + primitiveOp1() │
    │ + primitiveOp2() │
    └─────┬────────────┘
          │
    ┌─────┴────────┐
    ↓              ↓
┌──────────┐ ┌──────────┐
│Concrete  │ │Concrete  │
│Class1    │ │Class2    │
└──────────┘ └──────────┘

适用场景

  • 核心流程固定但部分步骤实现可变
  • 测试框架的用例执行流程
  • 报表生成系统(固定采集-处理-渲染流程)

优缺点分析

优势 劣势
流程代码复用率高 子类数量可能膨胀
  • 模板方法控制子类行为 | 模板方法修改影响所有子类 |
    | 符合开闭原则 | 步骤间依赖关系模糊 |

实际项目应用指南

选择依据

  • 多个子类有公共行为,但实现细节不同
  • 需要固定算法的执行顺序
  • 需要控制子类的扩展

使用技巧

java 复制代码
// 抽象类
public abstract class AbstractClass {
    // 模板方法,定义为final防止子类重写
    public final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();  // 钩子方法
    }
    
    // 抽象方法,由子类实现
    protected abstract void primitiveOperation1();
    protected abstract void primitiveOperation2();
    
    // 具体方法
    private void concreteOperation() {
        System.out.println("公共操作");
    }
    
    // 钩子方法,子类可选择重写
    protected void hook() {
        System.out.println("默认钩子方法");
    }
}

// 具体类A
public class ConcreteClassA extends AbstractClass {
    @Override
    protected void primitiveOperation1() {
        System.out.println("具体类A的操作1");
    }
    
    @Override
    protected void primitiveOperation2() {
        System.out.println("具体类A的操作2");
    }
    
    @Override
    protected void hook() {
        System.out.println("具体类A重写钩子方法");
    }
}

// 具体类B
public class ConcreteClassB extends AbstractClass {
    @Override
    protected void primitiveOperation1() {
        System.out.println("具体类B的操作1");
    }
    
    @Override
    protected void primitiveOperation2() {
        System.out.println("具体类B的操作2");
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        AbstractClass classA = new ConcreteClassA();
        classA.templateMethod();
        
        System.out.println("----------------");
        
        AbstractClass classB = new ConcreteClassB();
        classB.templateMethod();
    }
}

常见误区

  • ❌ 模板方法包含过多步骤导致职责混乱
  • ❅ 步骤间依赖关系模糊
  • ❌ 未使用final修饰模板方法

23. 访问者模式

核心特点

  • 分离数据结构与操作
  • 通过双分派机制实现差异化操作
  • 操作可独立扩展

UML类图描述

复制代码
    ┌──────────┐          ┌──────────┐
    │ Visitor  │          │ Element  │
    ├──────────┤          ├──────────┤
    │ + visit(A)│          │ + accept()│
    │ + visit(B)│          └────┬─────┘
    └──────────┘               │
             ↑                  ↑
    ┌────────┴──────┐    ┌─────┴──────┐
    ↓               ↓    ↓            ↓
┌──────────┐   ┌──────────┐ ┌──────┐ ┌──────┐
│Concrete  │   │Concrete  │ │Element│ │Element│
│Visitor   │   │Visitor   │ │  A   │ │  B   │
└──────────┘   └──────────┘ └──────┘ └──────┘

适用场景

  • 数据结构稳定但需频繁添加新操作
  • AST语法树解析
  • 数据库表操作(对不同表执行查询、统计)

优缺点分析

优势 劣势
操作扩展灵活 新增元素类需修改所有访问者
相似操作集中管理 双分派增加系统复杂度
  • 符合开闭原则 | 访问者依赖元素内部细节 |

实际项目应用指南

选择依据

  • 数据结构相对稳定
  • 需要对数据结构执行多种不同的操作
  • 操作逻辑需要集中管理

使用技巧

java 复制代码
// 访问者接口
public interface Visitor {
    void visit(ConcreteElementA elementA);
    void visit(ConcreteElementB elementB);
}

// 元素接口
public interface Element {
    void accept(Visitor visitor);
}

// 具体元素A
public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    public void operationA() {
        System.out.println("元素A的操作");
    }
}

// 具体元素B
public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    public void operationB() {
        System.out.println("元素B的操作");
    }
}

// 具体访问者
public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA elementA) {
        System.out.println("访问者处理元素A");
        elementA.operationA();
    }
    
    @Override
    public void visit(ConcreteElementB elementB) {
        System.out.println("访问者处理元素B");
        elementB.operationB();
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Element elementA = new ConcreteElementA();
        Element elementB = new ConcreteElementB();
        
        Visitor visitor = new ConcreteVisitor();
        
        elementA.accept(visitor);
        elementB.accept(visitor);
    }
}

常见误区

  • ❅ 元素类型频繁变化时使用
  • ❅ 访问者依赖元素内部细节
  • ❌ 未考虑双分派的性能开销

实际项目应用指南

创建型设计模式应用要点

模式 选择依据 关键技巧 常见误区
单例模式 全局唯一实例需求 枚举实现、DCL双检锁 忽略线程安全、序列化破坏
工厂方法 产品类型需扩展 依赖倒置、单一职责 工厂职责过重
抽象工厂 产品族协同工作 接口隔离、产品族一致性 产品族不稳定时误用
建造者模式 复杂对象分步构建 链式调用、静态内部类 与工厂模式混淆
原型模式 对象创建成本高 区分深浅拷贝 忽略嵌套对象引用

结构型设计模式应用要点

模式 选择依据 关键技巧 常见误区
适配器模式 接口不兼容 对象适配器(组合) 过度使用增加复杂度
桥接模式 多维度独立变化 组合优于继承 单一维度误用
组合模式 树形结构 递归遍历 叶子节点实现管理方法
装饰器模式 动态功能扩展 透明包裹 装饰链过长
外观模式 简化复杂系统 仅协调不添加逻辑 过度封装限制灵活性
享元模式 大量相似对象 分离内外状态 外部状态存储错误
代理模式 控制访问 静态/动态代理选择 与装饰器混淆

行为型设计模式应用要点

模式 选择依据 关键技巧 常见误区
责任链模式 动态处理链 设置默认处理者 链过长性能问题
命令模式 撤销/重做需求 命令粒度适中 命令对象状态过多
解释器模式 简单语法解析 递归结构 复杂语法误用
迭代器模式 统一遍历接口 fail-fast机制 依赖具体聚合类
中介者模式 复杂交互协调 按功能拆分中介者 中介者职责过重
备忘录模式 状态保存恢复 深拷贝实现 备忘录暴露内部状态
观察者模式 状态通知 观察者注销 忽略线程安全
状态模式 复杂状态转换 封装状态行为 状态类职责不清
策略模式 算法动态切换 结合工厂模式 客户端依赖具体策略
模板方法 流程固定步骤可变 final模板方法 步骤间依赖模糊
访问者模式 数据结构稳定操作多变 双分派机制 元素类型频繁变化

模式选择决策框架

决策框架设计原则

设计模式的选择应建立在问题驱动的底层逻辑之上,而非盲目追求技术实现。开发者需优先明确业务需求本质,再匹配适合的模式解决方案。

核心原则

  • 先明确问题边界与约束
  • 再从设计模式库中筛选匹配方案
  • 模式本质是经验抽象,而非银弹

评估三大核心因素

  1. 需求稳定性:高频变更场景适合策略模式
  2. 系统扩展性:组件复用需求适合装饰器模式
  3. 团队技术栈适配度:影响代理模式应用

设计模式选择决策树

复制代码
设计模式选择决策树

起点:判断核心问题类型
├─ 对象创建相关问题 → 创建型模式
│   ├─ 对象创建过程复杂且需解耦
│   │   ├─ 单一产品 → 工厂方法模式
│   │   └─ 产品族 → 抽象工厂模式
│   ├─ 控制实例数量或确保全局唯一
│   │   └─ 单例模式
│   └─ 动态指定对象类型或延迟初始化
│       ├─ 复制现有对象 → 原型模式
│       └─ 分步构建 → 建造者模式
│
├─ 类或对象组合问题 → 结构型模式
│   ├─ 接口不兼容需适配 → 适配器模式
│   ├─ 希望为对象添加额外功能 → 装饰器模式
│   ├─ 需统一复杂子系统访问接口 → 外观模式
│   ├─ 两个独立变化维度 → 桥接模式
│   ├─ 树形结构统一处理 → 组合模式
│   ├─ 控制对象访问 → 代理模式
│   └─ 大量相似对象复用 → 享元模式
│
└─ 对象交互协作问题 → 行为型模式
    ├─ 算法族需动态切换 → 策略模式
    ├─ 对象间需松耦合通信 → 观察者模式
    ├─ 复杂流程需分步控制
    │   ├─ 流程固定步骤可变 → 模板方法模式
    │   └─ 操作需记录/撤销 → 命令模式
    ├─ 请求处理者不确定或动态变化 → 责任链模式
    ├─ 对象状态多且转换复杂 → 状态模式
    ├─ 需遍历不同聚合结构 → 迭代器模式
    ├─ 多对象多对多交互 → 中介者模式
    ├─ 需保存/恢复状态 → 备忘录模式
    ├─ 简单语法解析 → 解释器模式
    └─ 数据结构稳定但需频繁添加新操作 → 访问者模式

决策框架应用示例

示例1:订单状态流转场景(行为型)

决策路径 :业务场景 → 行为型模式 → 对象状态多且转换复杂 → 状态模式

分析逻辑

  • 订单系统存在待支付、已支付、已发货、已完成等多种状态
  • 状态间转换规则复杂(如待支付超时自动取消)
  • 状态模式通过将不同状态封装为独立类,使状态转换逻辑与业务实体解耦
  • 符合"单一职责"原则,简化状态管理代码

示例2:日志框架设计场景(创建型+结构型)

决策路径 :业务场景 → 创建型模式 → 需要灵活创建不同日志对象 → 工厂方法模式

分析逻辑

  • 日志系统需支持控制台日志、文件日志、数据库日志等多种实现
  • 可能动态扩展新日志类型
  • 工厂方法模式通过定义日志对象的创建接口,由具体工厂类负责实例化特定类型的日志对象
  • 满足"开闭原则",提升框架的扩展性和可维护性

示例3:多条件校验场景(行为型)

决策路径 :业务场景 → 行为型模式 → 请求处理者不确定或动态变化 → 责任链模式

分析逻辑

  • 表单提交需要依次校验:非空校验 → 格式校验 → 业务规则校验
  • 校验规则可能动态增减
  • 责任链模式允许客户端动态配置校验顺序和规则
  • 实现校验逻辑与客户端的解耦

总结

设计模式是软件工程领域的经验结晶,但切记:

  1. 不要为了用模式而用模式------模式是解决问题的工具,而非目的
  2. 先理解问题本质------明确需求后再选择合适的模式
  3. 灵活运用------模式可以组合使用,也可以根据实际情况调整
  4. 持续学习------设计模式不是一成不变的,需要根据项目实践不断完善

掌握设计模式的核心不在于记住23种模式的定义,而在于理解它们背后的设计思想和解决问题的思维方式。在实际项目中,结合具体场景灵活运用,才能真正发挥设计模式的价值。

相关推荐
Desirediscipline2 小时前
cerr << 是C++中用于输出错误信息的标准用法
java·前端·c++·算法
Demon_Hao2 小时前
JAVA快速对接三方支付通道标准模版
java·开发语言
Renhao-Wan2 小时前
Java 算法实践(八):贪心算法思路
java·算法·贪心算法
w***71102 小时前
常见的 Spring 项目目录结构
java·后端·spring
野犬寒鸦3 小时前
深入解析HashMap核心机制(底层数据结构及扩容机制详解剖析)
java·服务器·开发语言·数据库·后端·面试
##学无止境##4 小时前
从0到1吃透Java负载均衡:原理与算法大揭秘
java·开发语言·负载均衡
梵得儿SHI4 小时前
Spring Cloud 核心组件精讲:负载均衡深度对比 Spring Cloud LoadBalancer vs Ribbon(原理 + 策略配置 + 性能优化)
java·spring cloud·微服务·负载均衡·架构原理·对比单体与微服务架构·springcloud核心组件
知识即是力量ol4 小时前
多线程并发篇(八股)
java·开发语言·八股·多线程并发
没有bug.的程序员4 小时前
Lombok 深度进阶:编译期增强内核、@Data 与 @Builder 逻辑博弈及工业级避坑实战指南
java·开发语言·python·builder·lombok·data·编译器增强