前排提醒:全文内容皆为OpenClaw生成,没有喂其他材料,内容准确性仅供参考。

设计模式完整笔记(通俗易懂版)

软考中级软件设计师考试专用 | GoF 23种设计模式


一、设计模式是什么

设计模式 = 套路,是前人总结的"这类问题就这样解决"的最佳实践。

就像武侠小说的"招式",记住套路就能见招拆招。

设计模式分为3大类

  • 创建型:对象怎么创建出来

  • 结构型:对象怎么组装起来

  • 行为型:对象怎么分工合作


二、创建型模式(5种)


1. 单例模式(Singleton)⭐⭐⭐

解决什么问题:我只需要一个对象,全世界都共享这一个。

生活类比

  • 地球只有一颗

  • 打印机的打印队列只有一份

代码实现(Java)

// 方式一:饿汉式(立即加载)
class Singleton {
    private static final Singleton instance = new Singleton();
    
    private Singleton() {}  // 私有构造函数
    
    public static Singleton getInstance() {
        return instance;
    }
}
​
// 方式二:懒汉式(延迟加载)
class SingletonLazy {
    private static SingletonLazy instance;
    
    private SingletonLazy() {}
    
    public static synchronized SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}
​
// 使用
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);  // true,都是同一个对象

考试要点

  • 构造函数私有

  • 只有一个实例

  • 全局访问点


2. 工厂方法模式(Factory Method)⭐⭐⭐

解决什么问题:对象创建太复杂,封装起来,不让调用者直接new。

生活类比

  • 你去工厂买车,不需要知道零件怎么组装

  • 直接说"我要买轿车"或"我要买卡车"

代码实现(Java)

// 产品接口
interface Phone {
    void call();
}
​
// 具体产品
class iPhone implements Phone {
    public void call() {
        System.out.println("用iPhone打电话");
    }
}
​
class AndroidPhone implements Phone {
    public void call() {
        System.out.println("用安卓手机打电话");
    }
}
​
// 工厂接口
interface PhoneFactory {
    Phone createPhone();
}
​
// 具体工厂
class AppleFactory implements PhoneFactory {
    public Phone createPhone() {
        return new iPhone();
    }
}
​
class SamsungFactory implements PhoneFactory {
    public Phone createPhone() {
        return new AndroidPhone();
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        PhoneFactory factory = new AppleFactory();
        Phone phone = factory.createPhone();
        phone.call();  // 输出:用iPhone打电话
    }
}

核心思想

"创建对象"抽象化,让子类决定创建什么对象。


3. 抽象工厂模式(Abstract Factory)⭐⭐⭐

解决什么问题:一个工厂能生产一整套相关产品。

生活类比

  • 汽车工厂不只生产车身,还生产发动机、轮胎

  • 一家人使用苹果全家桶(iPhone + Mac + iPad)

代码实现(Java)

// 产品族A
interface Button {
    void render();
}
interface Checkbox {
    void render();
}
​
// 产品族A的具体产品
class WindowsButton implements Button {
    public void render() { System.out.println("Windows按钮"); }
}
class WindowsCheckbox implements Checkbox {
    public void render() { System.out.println("Windows复选框"); }
}
​
// 产品族B的具体产品
class MacButton implements Button {
    public void render() { System.out.println("Mac按钮"); }
}
class MacCheckbox implements Checkbox {
    public void render() { System.out.println("Mac复选框"); }
}
​
// 抽象工厂
interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}
​
// 具体工厂
class WindowsFactory implements GUIFactory {
    public Button createButton() { return new WindowsButton(); }
    public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}
​
class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
    public Checkbox createCheckbox() { return new MacCheckbox(); }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        GUIFactory factory = new WindowsFactory();
        Button btn = factory.createButton();
        btn.render();  // Windows按钮
    }
}

工厂方法 vs 抽象工厂(对比!)

特征 工厂方法 抽象工厂
创建什么 一种产品 一族产品
工厂结构 一个方法 多个方法(一族)
复杂度 简单 复杂
适用场景 产品种类固定 产品族(多个相关产品)

记忆口诀

  • 工厂方法 = "一个方法产一种"

  • 抽象工厂 = "一个工厂产一套"


4. 建造者模式(Builder)⭐⭐

解决什么问题:对象太复杂,构造函数参数太多,用链式调用更清晰。

生活类比

  • 麦当劳点餐:汉堡 + 可乐 + 薯条 = 一个套餐

  • 可以单独选每一样

代码实现(Java)

// 产品:电脑
class Computer {
    private String cpu;
    private String gpu;
    private String memory;
    private String storage;
    
    // 私有构造函数(只能用Builder创建)
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.gpu = builder.gpu;
        this.memory = builder.memory;
        this.storage = builder.storage;
    }
    
    @Override
    public String toString() {
        return "Computer{cpu='" + cpu + "', gpu='" + gpu + 
               "', memory='" + memory + "', storage='" + storage + "'}";
    }
    
    // 建造者
    static class Builder {
        private String cpu = "默认CPU";
        private String gpu = "默认GPU";
        private String memory = "默认内存";
        private String storage = "默认硬盘";
        
        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;  // 链式调用
        }
        
        public Builder gpu(String gpu) {
            this.gpu = gpu;
            return this;
        }
        
        public Builder memory(String memory) {
            this.memory = memory;
            return this;
        }
        
        public Builder storage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        Computer gamingPC = new Computer.Builder()
            .cpu("Intel i9")
            .gpu("RTX 4090")
            .memory("64GB")
            .storage("2TB SSD")
            .build();
        
        Computer officePC = new Computer.Builder()
            .cpu("Intel i5")
            .memory("16GB")
            .build();
        
        System.out.println(gamingPC);
        // Computer{cpu='Intel i9', gpu='RTX 4090', memory='64GB', storage='2TB SSD'}
        System.out.println(officePC);
        // Computer{cpu='Intel i5', gpu='默认GPU', memory='16GB', storage='默认硬盘'}
    }
}

5. 原型模式(Prototype)⭐

解决什么问题:复制一个对象,不暴露创建细节。

生活类比

  • 细胞分裂:从一个细胞复制出另一个

  • 复印文件:复印机复制文件

代码实现(Java)

// 原型接口
interface Cloneable {
    Cloneable clone();
}
​
// 具体原型
class Student implements Cloneable {
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public Student clone() {
        return new Student(this.name, this.age);
    }
    
    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + "}";
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        Student original = new Student("张三", 20);
        Student copy = original.clone();
        
        System.out.println(original);  // Student{name='张三', age=20}
        System.out.println(copy);     // Student{name='张三', age=20}
        System.out.println(original == copy);  // false,不是同一个对象
    }
}

三、结构型模式(7种)


6. 适配器模式(Adapter)⭐⭐⭐

解决什么问题:接口不兼容,加个"转换器"让他们能一起工作。

生活类比

  • 手机充电头:欧标插头 → 转接头 → 中国插座

  • 翻译:把A语言翻译成B语言

代码实现(Java)

// 目标接口(你想要什么)
interface MediaPlayer {
    void play(String filename);
}
​
// 已存在的类(你有的是什么)
class MP3Player {
    public void playMP3(String file) {
        System.out.println("播放MP3: " + file);
    }
}
​
// 适配器(转换器)
class MediaAdapter implements MediaPlayer {
    private MP3Player mp3Player;
    
    public MediaAdapter() {
        this.mp3Player = new MP3Player();
    }
    
    @Override
    public void play(String filename) {
        // 把MediaPlayer的play转换为MP3Player能理解的playMP3
        mp3Player.playMP3(filename);
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        MediaPlayer player = new MediaAdapter();
        player.play("song.mp3");  // 输出:播放MP3: song.mp3
    }
}

7. 装饰器模式(Decorator)⭐⭐⭐

解决什么问题:功能要动态增加,但不是用继承(避免类爆炸)。

生活类比

  • 手机壳 + 挂件 = 给手机加装饰

  • 咖啡 + 牛奶 + 糖 = 逐步加料

代码实现(Java)

// 基础接口
interface Coffee {
    String getDescription();
    double getCost();
}
​
// 基础实现
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }
    
    @Override
    public double getCost() {
        return 20.0;
    }
}
​
// 装饰器基类
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}
​
// 具体装饰器:加牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 牛奶";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 5.0;
    }
}
​
// 具体装饰器:加糖
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 糖";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 2.0;
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        // 浓缩咖啡
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " = " + coffee.getCost());
        // 浓缩咖啡 = 20.0
        
        // 加牛奶
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " = " + coffee.getCost());
        // 浓缩咖啡 + 牛奶 = 25.0
        
        // 再加糖
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " = " + coffee.getCost());
        // 浓缩咖啡 + 牛奶 + 糖 = 27.0
    }
}

适配器 vs 装饰器(对比!)

特征 适配器 装饰器
目的 让不兼容的能一起工作 给对象动态加功能
关系 "转换器" "包装"
调用方式 调用转换后的方法 委托给被包装对象
使用场景 旧系统接口 → 新需求 功能扩展

记忆口诀

  • 适配器 = "转换插头"

  • 装饰器 = "套包装"


8. 代理模式(Proxy)⭐⭐⭐

解决什么问题:不能直接访问对象,通过代理来控制访问。

生活类比

  • 房产中介:买家 → 中介 → 房东

  • VPN:电脑 → 代理服务器 → 目标网站

代码实现(Java)

// 真实主题(真正做事的人)
class RealImage {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("从磁盘加载: " + filename);
    }
    
    public void display() {
        System.out.println("显示图片: " + filename);
    }
}
​
// 代理(控制访问)
class ImageProxy {
    private String filename;
    private RealImage realImage;  // 延迟加载
    
    public ImageProxy(String filename) {
        this.filename = filename;
    }
    
    public void display() {
        // 懒加载:第一次才加载真实对象
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        ImageProxy proxy = new ImageProxy("大图片.jpg");
        
        System.out.println("--- 创建代理完毕 ---");
        // 此时没有加载真实图片
        
        proxy.display();  // 第一次调用才加载
        // 从磁盘加载: 大图片.jpg
        // 显示图片: 大图片.jpg
        
        proxy.display();  // 第二次直接用缓存
        // 显示图片: 大图片.jpg
    }
}

9. 组合模式(Composite)⭐⭐

解决什么问题:树形结构,整体和部分用同一套接口。

生活类比

  • 文件夹里有文件,也有子文件夹

  • 公司有部门,部门里还有子部门

代码实现(Java)

// 抽象组件
abstract class FileSystemComponent {
    protected String name;
    
    public FileSystemComponent(String name) {
        this.name = name;
    }
    
    abstract void display(String indent);
}

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

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

// 使用
public class Main {
    public static void main(String[] args) {
        Folder root = new Folder("C盘");
        Folder docs = new Folder("文档");
        Folder pictures = new Folder("图片");
        
        docs.add(new File("简历.docx"));
        docs.add(new File("报告.pdf"));
        
        pictures.add(new File("风景.jpg"));
        
        root.add(docs);
        root.add(pictures);
        
        root.display("");
        // + 文件夹: C盘
        //   + 文件夹: 文档
        //     - 文件: 简历.docx
        //     - 文件: 报告.pdf
        //   + 文件夹: 图片
        //     - 文件: 风景.jpg
    }
}

10. 外观模式(Facade)⭐⭐

解决什么问题:子系统太复杂,给一个统一的入口。

生活类比

  • 电视遥控器:一个按钮控制电源、音量、频道

  • 一键下单:内部调用N个接口,外部只看到一个接口

代码实现(Java)

// 子系统A
class CPU {
    public void start() { System.out.println("CPU启动"); }
    public void shutdown() { System.out.println("CPU关闭"); }
}

// 子系统B
class Memory {
    public void load() { System.out.println("内存加载"); }
    public void refresh() { System.out.println("内存刷新"); }
}

// 子系统C
class Disk {
    public void read() { System.out.println("磁盘读取"); }
    public void write() { System.out.println("磁盘写入"); }
}

// 外观类(统一入口)
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private Disk disk;
    
    public ComputerFacade() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.disk = new Disk();
    }
    
    public void startComputer() {
        System.out.println("=== 开机启动 ===");
        cpu.start();
        memory.load();
        disk.read();
        System.out.println("=== 开机完成 ===");
    }
    
    public void shutdownComputer() {
        System.out.println("=== 关机 ===");
        disk.write();
        memory.refresh();
        cpu.shutdown();
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.startComputer();
        // === 开机启动 ===
        // CPU启动
        // 内存加载
        // 磁盘读取
        // === 开机完成 ===
        
        computer.shutdownComputer();
    }
}

11. 桥接模式(Bridge)⭐⭐

解决什么问题:两个维度独立变化,互不影响。

生活类比

  • 手机品牌(华为、苹果)× 功能(打电话、发短信)

  • 形状(圆形、方形)× 颜色(红色、蓝色)

代码实现(Java)

// 维度1:品牌(抽象)
abstract class PhoneBrand {
    protected PhoneSoftware software;  // 桥接到另一个维度
    
    public void setSoftware(PhoneSoftware software) {
        this.software = software;
    }
    
    abstract void launch();
}

// 维度2:软件(抽象)
interface PhoneSoftware {
    void run();
}

// 具体品牌
class HuaweiPhone extends PhoneBrand {
    @Override
    void launch() {
        System.out.print("华为手机启动: ");
        software.run();
    }
}

class ApplePhone extends PhoneBrand {
    @Override
    void launch() {
        System.out.print("苹果手机启动: ");
        software.run();
    }
}

// 具体软件
class WeChat implements PhoneSoftware {
    @Override
    public void run() {
        System.out.println("微信运行中");
    }
}

class TikTok implements PhoneSoftware {
    @Override
    public void run() {
        System.out.println("抖音运行中");
    }
}

// 使用 - 两个维度可以自由组合
public class Main {
    public static void main(String[] args) {
        PhoneBrand huawei = new HuaweiPhone();
        PhoneBrand apple = new ApplePhone();
        
        huawei.setSoftware(new WeChat());
        huawei.launch();  // 华为手机启动: 微信运行中
        
        huawei.setSoftware(new TikTok());
        huawei.launch();  // 华为手机启动: 抖音运行中
        
        apple.setSoftware(new WeChat());
        apple.launch();  // 苹果手机启动: 微信运行中
    }
}

适配器 vs 桥接 vs 装饰器(对比!)

模式 目的 关系 编译时/运行时
适配器 让不兼容的能一起工作 "转换器" 运行时
桥接 两个维度独立变化 "桥接" 编译时
装饰器 动态增加功能 "包装" 运行时

四、行为型模式(11种)


12. 观察者模式(Observer)⭐⭐⭐

解决什么问题:一个对象变化,通知所有依赖它的对象。

生活类比

  • 微信公众号:作者发文章 → 所有订阅者收到通知

  • 气象站:温度变化 → 所有显示板自动更新

代码实现(Java)

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

// 具体主题
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
    
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyAll();  // 温度变化,通知所有观察者
    }
    
    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyAll() {
        for (Observer o : observers) {
            o.update(temperature);
        }
    }
}

// 观察者接口
interface Observer {
    void update(float temperature);
}

// 具体观察者
class PhoneDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("手机显示: 温度=" + temperature + "°C");
    }
}

class TVDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("电视显示: 当前温度 " + temperature + "°C");
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        
        Observer phone = new PhoneDisplay();
        Observer tv = new TVDisplay();
        
        station.attach(phone);
        station.attach(tv);
        
        station.setTemperature(25.5f);
        // 手机显示: 温度=25.5°C
        // 电视显示: 当前温度 25.5°C
        
        station.setTemperature(30.0f);
        // 手机显示: 温度=30.0°C
        // 电视显示: 当前温度 30.0°C
    }
}

13. 策略模式(Strategy)⭐⭐⭐

解决什么问题:不同的算法/策略可以互换。

生活类比

  • 出行方式:开车、坐地铁、骑自行车

  • 支付方式:微信、支付宝、现金

代码实现(Java)

// 策略接口
interface PaymentStrategy {
    void pay(double amount);
}

// 具体策略
class WeChatPay implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付 ¥" + amount);
    }
}

class AliPay implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付 ¥" + amount);
    }
}

class CashPay implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("现金支付 ¥" + amount);
    }
}

// 环境类(使用策略)
class ShoppingCart {
    private List<Double> prices = new ArrayList<>();
    private PaymentStrategy strategy;  // 可以随时切换
    
    public void addPrice(double price) {
        prices.add(price);
    }
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void checkout() {
        double total = prices.stream().mapToDouble(Double::doubleValue).sum();
        strategy.pay(total);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        cart.addPrice(100);
        cart.addPrice(50);
        cart.addPrice(30);
        
        // 用微信支付
        cart.setPaymentStrategy(new WeChatPay());
        cart.checkout();  // 微信支付 ¥180.0
        
        // 换支付宝
        cart.setPaymentStrategy(new AliPay());
        cart.checkout();  // 支付宝支付 ¥180.0
    }
}

策略模式 vs 状态模式(对比!)

特征 策略模式 状态模式
关注点 算法/行为可以互换 对象内部状态决定行为
切换方式 外部指定 内部自动切换
关系 平等,可互换 状态决定下一个状态

记忆口诀

  • 策略 = "你选算法"

  • 状态 = "状态自己变"


14. 命令模式(Command)⭐⭐

解决什么问题:把"请求"封装成对象,可以撤销、排队。

生活类比

  • 遥控器:按下"开灯"按钮 → 灯亮了

  • 餐厅点单:服务员记下订单 → 厨师做菜

代码实现(Java)

// 命令接口
interface Command {
    void execute();
    void undo();  // 支持撤销
}

// 具体命令
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();
    }
}

class Light {
    public void on() { System.out.println("灯亮了"); }
    public void off() { System.out.println("灯灭了"); }
}

// 调用者(遥控器)
class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
    
    public void pressUndo() {
        command.undo();
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        
        RemoteControl remote = new RemoteControl();
        remote.setCommand(lightOn);
        
        remote.pressButton();   // 灯亮了
        remote.pressUndo();      // 灯灭了
    }
}

15. 模板方法模式(Template Method)⭐⭐

解决什么问题:算法骨架固定,某些步骤由子类实现。

生活类比

  • 做菜流程:准备 → 烹饪 → 装盘(固定)

  • 具体做什么菜,子类决定

代码实现(Java)

// 抽象父类(定义骨架)
abstract class Beverage {
    // 模板方法(算法骨架)
    public final void makeBeverage() {
        boilWater();        // 1. 烧水(固定)
        brew();             // 2. 冲泡(子类实现)
        pourInCup();        // 3. 倒杯(固定)
        addCondiments();    // 4. 加调料(子类实现)
    }
    
    // 固定步骤
    private void boilWater() {
        System.out.println("烧水");
    }
    
    private void pourInCup() {
        System.out.println("倒杯");
    }
    
    // 子类实现步骤
    abstract void brew();
    abstract void addCondiments();
}

// 具体子类:茶
class Tea extends Beverage {
    @Override
    void brew() {
        System.out.println("冲泡茶叶");
    }
    
    @Override
    void addCondiments() {
        System.out.println("加柠檬");
    }
}

// 具体子类:咖啡
class Coffee extends Beverage {
    @Override
    void brew() {
        System.out.println("冲泡咖啡粉");
    }
    
    @Override
    void addCondiments() {
        System.out.println("加糖和奶");
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Beverage tea = new Tea();
        tea.makeBeverage();
        // 烧水
        // 冲泡茶叶
        // 倒杯
        // 加柠檬
        
        System.out.println("---");
        
        Beverage coffee = new Coffee();
        coffee.makeBeverage();
        // 烧水
        // 冲泡咖啡粉
        // 倒杯
        // 加糖和奶
    }
}

16. 迭代器模式(Iterator)⭐⭐

解决什么问题:遍历集合不用知道集合内部结构。

生活类比

  • 书架遍历:不管书架怎么排,书一本一本拿

  • 电视遥控器的频道切换按钮

代码实现(Java)

// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 具体迭代器
class BookIterator implements Iterator {
    private BookCollection collection;
    private int position = 0;
    
    public BookIterator(BookCollection collection) {
        this.collection = collection;
    }
    
    @Override
    public boolean hasNext() {
        return position < collection.getBooks().size();
    }
    
    @Override
    public Object next() {
        return collection.getBooks().get(position++);
    }
}

// 集合接口
interface Collection {
    Iterator createIterator();
}

// 具体集合
class BookCollection implements Collection {
    private List<String> books = new ArrayList<>();
    
    public void addBook(String book) {
        books.add(book);
    }
    
    public List<String> getBooks() {
        return books;
    }
    
    @Override
    public Iterator createIterator() {
        return new BookIterator(this);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        BookCollection collection = new BookCollection();
        collection.addBook("《设计模式》");
        collection.addBook("《算法导论》");
        collection.addBook("《编译原理》");
        
        Iterator iterator = collection.createIterator();
        while (iterator.hasNext()) {
            System.out.println("书: " + iterator.next());
        }
        // 书: 《设计模式》
        // 书: 《算法导论》
        // 书: 《编译原理》
    }
}

17. 责任链模式(Chain of Responsibility)⭐⭐

解决什么问题:请求一级一级传递,直到有人处理。

生活类比

  • 审批流程:主任 → 部长 → 总经理

  • 客户投诉:客服 → 组长 → 经理

代码实现(Java)

// 抽象处理者
abstract class Handler {
    protected Handler nextHandler;
    
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
    
    public abstract void handleRequest(String request);
}

// 具体处理者
class Director extends Handler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("请假1天")) {
            System.out.println("主任审批通过: " + request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

class Manager extends Handler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("请假3天")) {
            System.out.println("经理审批通过: " + request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

class Boss extends Handler {
    @Override
    public void handleRequest(String request) {
        System.out.println("老板审批: " + request);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Handler director = new Director();
        Handler manager = new Manager();
        Handler boss = new Boss();
        
        director.setNextHandler(manager);
        manager.setNextHandler(boss);
        
        director.handleRequest("请假1天");  // 主任审批
        director.handleRequest("请假3天");  // 经理审批
        director.handleRequest("请假10天"); // 老板审批
    }
}

18. 状态模式(State)⭐⭐

解决什么问题:对象内部状态决定行为,状态自动切换。

代码实现(Java)

// 状态接口
interface State {
    void insertCoin(Context context);    // 投入硬币
    void pushButton(Context context);    // 按按钮
    void dispense(Context context);      // 出商品
}

// 具体状态
class NoCoinState implements State {
    @Override
    public void insertCoin(Context context) {
        System.out.println("硬币已投入");
        context.setState(new HasCoinState());
    }
    
    @Override
    public void pushButton(Context context) {
        System.out.println("请先投币");
    }
    
    @Override
    public void dispense(Context context) {}
}

class HasCoinState implements State {
    @Override
    public void insertCoin(Context context) {
        System.out.println("已有硬币,请按按钮");
    }
    
    @Override
    public void pushButton(Context context) {
        System.out.println("按钮已按下,商品准备中");
        context.setState(new DispenseState());
    }
    
    @Override
    public void dispense(Context context) {}
}

class DispenseState implements State {
    @Override
    public void insertCoin(Context context) {}
    
    @Override
    public void pushButton(Context context) {}
    
    @Override
    public void dispense(Context context) {
        System.out.println("商品已出");
        context.setState(new NoCoinState());
    }
}

// 环境类(持有状态)
class Context {
    private State state = new NoCoinState();
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void insertCoin() {
        state.insertCoin(this);
    }
    
    public void pushButton() {
        state.pushButton(this);
    }
    
    public void dispense() {
        state.dispense(this);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Context machine = new Context();
        
        machine.pushButton();  // 请先投币
        machine.insertCoin();  // 硬币已投入
        machine.pushButton();  // 按钮已按下,商品准备中
        machine.dispense();    // 商品已出
    }
}

19. 备忘录模式(Memento)⭐

解决什么问题:保存对象状态,随时可恢复。

生活类比

  • 游戏存档:打Boss前存档,打输了就读档

  • Word撤销:Ctrl+Z

代码实现(Java)

// 备忘录(存档)
class Memento {
    private String state;
    
    public Memento(String state) {
        this.state = state;
    }
    
    public String getState() {
        return state;
    }
}

// 原发器(游戏角色)
class GameRole {
    private int vitality = 100;  // 生命值
    private int attack = 50;      // 攻击力
    
    // 保存状态
    public Memento save() {
        return new Memento("生命力:" + vitality + ",攻击力:" + attack);
    }
    
    // 恢复状态
    public void restore(Memento memento) {
        String state = memento.getState();
        System.out.println("恢复状态: " + state);
    }
    
    public void fight() {
        vitality -= 80;
        attack += 10;
        System.out.println("战斗后: 生命力=" + vitality);
    }
    
    public int getVitality() {
        return vitality;
    }
}

// 管理者(存档管理器)
class Caretaker {
    private Memento memento;
    
    public void saveMemento(Memento memento) {
        this.memento = memento;
    }
    
    public Memento getMemento() {
        return this.memento;
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        GameRole role = new GameRole();
        Caretaker caretaker = new Caretaker();
        
        // 打Boss前存档
        caretaker.saveMemento(role.save());
        System.out.println("存档完成,当前生命力: " + role.getVitality());
        
        // 打Boss
        role.fight();
        
        // 打输了,恢复存档
        role.restore(caretaker.getMemento());
    }
}

20. 享元模式(Flyweight)⭐

解决什么问题:大量相似对象,共享相同部分,只创建不同部分。

生活类比

  • 文字处理:文档中所有"字母A"共用同一个字体对象

  • 游戏:大量子弹共用同一张贴图

代码实现(Java)

// 享元接口
interface TreeType {
    void draw(int x, int y);  // 不同位置画同一棵树
}
​
// 具体享元(共享)
class CommonTree implements TreeType {
    private String name;  // 内在状态(可共享)
    private String color;  // 内在状态(可共享)
    
    public CommonTree(String name, String color) {
        this.name = name;
        this.color = color;
    }
    
    @Override
    public void draw(int x, int y) {
        // x, y 是外在状态(不可共享,每个位置不同)
        System.out.println("在(" + x + "," + y + ")绘制" + color + name);
    }
}
​
// 享元工厂
class TreeFactory {
    private static Map<String, TreeType> treeTypes = new HashMap<>();
    
    public static TreeType getTreeType(String name, String color) {
        String key = name + "-" + color;
        if (!treeTypes.containsKey(key)) {
            treeTypes.put(key, new CommonTree(name, color));
            System.out.println("创建新树: " + key);
        }
        return treeTypes.get(key);
    }
}
​
// 使用
public class Main {
    public static void main(String[] args) {
        // 创建10000棵树,但只存储3个享元对象
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            int x = random.nextInt(100);
            int y = random.nextInt(100);
            TreeType tree = TreeFactory.getTreeType("松树", "绿色");
            tree.draw(x, y);
        }
        // 输出:创建新树: 松树-绿色
        // 然后全部复用同一个对象
    }
}

21. 中介者模式(Mediator)⭐

解决什么问题:对象之间不直接通信,通过中介者转发。

生活类比

  • 机场调度中心:飞机不直接对话,都找调度中心

  • 房产中介:买家和卖家不直接见面,都通过中介

代码实现(Java)

// 中介者接口
interface ChatMediator {
    void sendMessage(String msg, User user);
    void addUser(User user);
}

// 具体中介者
class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();
    
    @Override
    public void addUser(User user) {
        users.add(user);
    }
    
    @Override
    public void sendMessage(String msg, User sender) {
        for (User u : users) {
            if (u != sender) {  // 不发给自己
                u.receive(msg);
            }
        }
    }
}

// 同事类(参与者)
class User {
    private String name;
    private ChatMediator mediator;
    
    public User(String name, ChatMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }
    
    public void send(String msg) {
        System.out.println(name + " 发送: " + msg);
        mediator.sendMessage(msg, this);
    }
    
    public void receive(String msg) {
        System.out.println(name + " 收到: " + msg);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        ChatMediator chat = new ChatRoom();
        
        User alice = new User("Alice", chat);
        User bob = new User("Bob", chat);
        User charlie = new User("Charlie", chat);
        
        chat.addUser(alice);
        chat.addUser(bob);
        chat.addUser(charlie);
        
        alice.send("大家好!");
        // Alice 发送: 大家好!
        // Bob 收到: 大家好!
        // Charlie 收到: 大家好!
    }
}

22. 解释器模式(Interpreter)⭐

解决什么问题:用对象表示语法规则,执行表达式。

生活类比

  • 计算器:把 "1 + 2" 解析成语法树,然后计算

  • 音乐简谱:把音符翻译成演奏指令

代码实现(Java)

// 表达式接口
interface Expression {
    int interpret(Map<String, Integer> context);
}

// 终结符表达式
class NumberExpression implements Expression {
    private int number;
    
    public NumberExpression(int number) {
        this.number = number;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        return number;
    }
}

// 变量表达式
class VariableExpression implements Expression {
    private String name;
    
    public VariableExpression(String name) {
        this.name = name;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        return context.getOrDefault(name, 0);
    }
}

// 加法表达式
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(Map<String, Integer> context) {
        return left.interpret(context) + right.interpret(context);
    }
}

// 使用:(x + 5) - y
public class Main {
    public static void main(String[] args) {
        Map<String, Integer> context = new HashMap<>();
        context.put("x", 10);
        context.put("y", 3);
        
        // (x + 5) - y
        Expression expr = new AddExpression(
            new VariableExpression("x"),
            new NumberExpression(5)
        );
        int result = expr.interpret(context);
        System.out.println("(x + 5) = " + result);  // 15
    }
}

23. 访问者模式(Visitor)⭐

解决什么问题:对一组对象操作,但不想改对象类。

生活类比

  • 体检中心:不同的检查设备(访问者)访问同一个人

  • 海关检查:海关人员(访问者)检查不同货物(元素)

代码实现(Java)

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

// 具体元素
class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    public double getRadius() {
        return radius;
    }
    
    @Override
    public void accept(Visitor visitor) {
        visitor.visitCircle(this);
    }
}

class Rectangle implements Shape {
    private double width, height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void accept(Visitor visitor) {
        visitor.visitRectangle(this);
    }
}

// 访问者接口
interface Visitor {
    void visitCircle(Circle circle);
    void visitRectangle(Rectangle rectangle);
}

// 具体访问者:计算面积
class AreaVisitor implements Visitor {
    @Override
    public void visitCircle(Circle circle) {
        double area = Math.PI * circle.getRadius() * circle.getRadius();
        System.out.println("圆面积: " + area);
    }
    
    @Override
    public void visitRectangle(Rectangle rectangle) {
        double area = rectangle.width * rectangle.height;
        System.out.println("矩形面积: " + area);
    }
}

// 具体访问者:绘制边框
class DrawVisitor implements Visitor {
    @Override
    public void visitCircle(Circle circle) {
        System.out.println("绘制圆,半径=" + circle.getRadius());
    }
    
    @Override
    public void visitRectangle(Rectangle rectangle) {
        System.out.println("绘制矩形,宽=" + rectangle.width + ",高=" + rectangle.height);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        List<Shape> shapes = Arrays.asList(
            new Circle(5),
            new Rectangle(4, 6)
        );
        
        Visitor areaVisitor = new AreaVisitor();
        Visitor drawVisitor = new DrawVisitor();
        
        System.out.println("=== 计算面积 ===");
        for (Shape s : shapes) {
            s.accept(areaVisitor);
        }
        // 圆面积: 78.54
        // 矩形面积: 24.0
        
        System.out.println("=== 绘制 ===");
        for (Shape s : shapes) {
            s.accept(drawVisitor);
        }
    }
}

五、全部模式速查表

创建型(5种)

模式 目的 考频
单例 只有一个实例 ★★★
工厂方法 子类决定创建什么 ★★★
抽象工厂 产一套产品 ★★★
建造者 链式创建复杂对象 ★★
原型 复制对象

结构型(7种)

模式 目的 考频
适配器 接口转换 ★★★
装饰器 动态加功能 ★★★
代理 控制访问 ★★★
组合 树形结构 ★★
外观 统一入口 ★★
桥接 两个维度独立变化 ★★
享元 共享细粒度对象

行为型(11种)

模式 目的 考频
观察者 一对多通知 ★★★
策略 算法互换 ★★★
命令 请求封装 ★★
模板方法 算法骨架 ★★
迭代器 遍历集合 ★★
责任链 一级级传递 ★★
状态 状态决定行为 ★★
备忘录 保存/恢复状态
中介者 对象间接通信
解释器 语法解析
访问者 操作分离

六、易混模式对比汇总

对比组 区别
工厂方法 vs 抽象工厂 一个产一种 vs 一个产一套
策略 vs 状态 外部选 vs 内部自动切
适配器 vs 装饰器 转换 vs 包装加功能
适配器 vs 桥接 转换接口 vs 连接两个维度
装饰器 vs 代理 加功能 vs 控制访问
组合 vs 聚合 强整体 vs 弱整体
观察者 vs 中介者 直接通知 vs 间接传话
命令 vs 策略 请求封装 vs 算法互换

整理时间:2026-05-22 通俗易懂版

更多推荐