前言

设计模式可以理解为软件开发中反复出现的问题所对应的一套通用解决方案。

GoF 设计模式一共有 23 种,通常分为三大类:

  • 创建型模式:关注对象怎么创建

  • 结构型模式:关注类和对象怎么组合

  • 行为型模式:关注对象之间怎么协作

一句话理解:

创建型解决「怎么创建对象」,结构型解决「怎么组织对象」,行为型解决「对象之间怎么配合完成行为」。

一、设计模式三大分类

分类数量关注点包含模式
创建型模式5 种对象创建过程单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式
结构型模式7 种类或对象的组合结构适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、代理模式
行为型模式11 种对象之间的职责分配和协作模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、备忘录模式、迭代器模式、访问者模式、解释器模式

二、23 种设计模式总览

序号模式类型核心作用
1单例模式创建型保证一个类只有一个实例
2工厂方法模式创建型由子类决定创建哪一种对象
3抽象工厂模式创建型创建一组相关对象
4建造者模式创建型分步骤创建复杂对象
5原型模式创建型通过复制已有对象创建新对象
6适配器模式结构型让不兼容的接口可以一起工作
7桥接模式结构型把抽象和实现分离,使二者可以独立变化
8组合模式结构型用树形结构表示整体和部分
9装饰器模式结构型动态增强对象功能
10外观模式结构型为复杂子系统提供统一入口
11享元模式结构型共享对象,减少内存占用
12代理模式结构型通过代理对象控制对真实对象的访问
13模板方法模式行为型父类定义流程,子类实现细节
14策略模式行为型封装不同算法并可相互替换
15命令模式行为型把请求封装成对象
16职责链模式行为型多个处理者按链路依次处理请求
17状态模式行为型对象行为随状态变化而变化
18观察者模式行为型一个对象变化时通知多个依赖对象
19中介者模式行为型用中介对象协调多个对象交互
20备忘录模式行为型保存和恢复对象历史状态
21迭代器模式行为型顺序访问集合元素而不暴露内部结构
22访问者模式行为型在不修改对象结构的情况下新增操作
23解释器模式行为型为特定语法提供解释执行能力

三、创建型模式

创建型模式关注的是对象的创建过程。它们的目标是把对象创建逻辑从业务代码中抽离出来,让代码更灵活、更容易扩展。


1. 单例模式

定义

单例模式保证一个类在系统中只有一个实例,并提供一个全局访问点。

方便理解

有些对象不需要创建多个,比如配置中心、线程池、日志对象。如果到处都 new,会浪费资源,也容易造成状态不一致。

单例模式就是让这个类只创建一次,后面都复用同一个对象。

代码示例

public class ConfigManager {
    private static final ConfigManager INSTANCE = new ConfigManager();

    private ConfigManager() {
    }

    public static ConfigManager getInstance() {
        return INSTANCE;
    }

    public String getConfig(String key) {
        return "value of " + key;
    }
}

class SingletonDemo {
    public static void main(String[] args) {
        ConfigManager config1 = ConfigManager.getInstance();
        ConfigManager config2 = ConfigManager.getInstance();

        System.out.println(config1 == config2);
    }
}

适用场景

  • 配置管理器

  • 日志对象

  • 线程池

  • 缓存对象

  • 需要全局唯一实例的对象

    2. 工厂方法模式

    定义

    工厂方法模式定义一个创建对象的接口,但由子类决定具体创建哪一种对象。

    方便理解

    可以把它理解成「父类规定要生产产品,但具体生产什么产品交给子类决定」。

    比如不同平台都要创建按钮,Windows 平台创建 Windows 按钮,Mac 平台创建 Mac 按钮。

    代码示例

    interface Button {
        void render();
    }
    
    class WindowsButton implements Button {
        @Override
        public void render() {
            System.out.println("渲染 Windows 按钮");
        }
    }
    
    class MacButton implements Button {
        @Override
        public void render() {
            System.out.println("渲染 Mac 按钮");
        }
    }
    
    abstract class Dialog {
        public void show() {
            Button button = createButton();
            button.render();
        }
    
        protected abstract Button createButton();
    }
    
    class WindowsDialog extends Dialog {
        @Override
        protected Button createButton() {
            return new WindowsButton();
        }
    }
    
    class MacDialog extends Dialog {
        @Override
        protected Button createButton() {
            return new MacButton();
        }
    }

    适用场景

  • 不确定要创建哪一种具体对象

  • 创建对象的逻辑需要延迟到子类

  • 希望新增产品时减少对原有代码的修改

    3. 抽象工厂模式

    定义

    抽象工厂模式用于创建一组相关或相互依赖的对象,而不需要指定它们的具体类。

    方便理解

    工厂方法模式通常创建一个产品,抽象工厂模式创建一组产品。

    例如一套 UI 主题中,按钮、输入框、复选框都应该属于同一种风格。

    代码示例

    interface Button {
        void render();
    }
    
    interface Checkbox {
        void render();
    }
    
    class LightButton implements Button {
        @Override
        public void render() {
            System.out.println("浅色按钮");
        }
    }
    
    class LightCheckbox implements Checkbox {
        @Override
        public void render() {
            System.out.println("浅色复选框");
        }
    }
    
    class DarkButton implements Button {
        @Override
        public void render() {
            System.out.println("深色按钮");
        }
    }
    
    class DarkCheckbox implements Checkbox {
        @Override
        public void render() {
            System.out.println("深色复选框");
        }
    }
    
    interface UIFactory {
        Button createButton();
    
        Checkbox createCheckbox();
    }
    
    class LightUIFactory implements UIFactory {
        @Override
        public Button createButton() {
            return new LightButton();
        }
    
        @Override
        public Checkbox createCheckbox() {
            return new LightCheckbox();
        }
    }
    
    class DarkUIFactory implements UIFactory {
        @Override
        public Button createButton() {
            return new DarkButton();
        }
    
        @Override
        public Checkbox createCheckbox() {
            return new DarkCheckbox();
        }
    }

    适用场景

  • 需要创建一组相关对象

  • 产品之间有风格、平台或主题上的一致性要求

  • 不希望业务代码依赖具体产品类

4. 建造者模式

定义

建造者模式把复杂对象的创建过程拆分成多个步骤,使同样的构建过程可以创建不同表示的对象。

方便理解

如果一个对象字段很多,构造方法参数会越来越长,可读性很差。

建造者模式就像点套餐,可以一步一步选择 CPU、内存、硬盘,最后生成一台电脑。

代码示例

class Computer {
    private String cpu;
    private String memory;
    private String disk;

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setDisk(String disk) {
        this.disk = disk;
    }

    @Override
    public String toString() {
        return cpu + ", " + memory + ", " + disk;
    }
}

class ComputerBuilder {
    private final Computer computer = new Computer();

    public ComputerBuilder cpu(String cpu) {
        computer.setCpu(cpu);
        return this;
    }

    public ComputerBuilder memory(String memory) {
        computer.setMemory(memory);
        return this;
    }

    public ComputerBuilder disk(String disk) {
        computer.setDisk(disk);
        return this;
    }

    public Computer build() {
        return computer;
    }
}

class BuilderDemo {
    public static void main(String[] args) {
        Computer computer = new ComputerBuilder()
                .cpu("Intel i7")
                .memory("32GB")
                .disk("1TB SSD")
                .build();

        System.out.println(computer);
    }
}

适用场景

  • 对象字段很多

  • 构造过程复杂

  • 希望链式创建对象

  • 需要避免过长的构造方法参数

    5. 原型模式

    定义

    原型模式通过复制已有对象来创建新对象,而不是每次都从头创建。

    方便理解

    如果创建一个对象成本很高,比如需要加载大量数据,可以先准备一个原型对象,后续直接复制它。

    代码示例

    class Document implements Cloneable {
        private String title;
        private String content;
    
        public Document(String title, String content) {
            this.title = title;
            this.content = content;
        }
    
        @Override
        public Document clone() {
            try {
                return (Document) super.clone();
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        @Override
        public String toString() {
            return title + ": " + content;
        }
    }
    
    class PrototypeDemo {
        public static void main(String[] args) {
            Document template = new Document("模板", "固定内容");
            Document copy = template.clone();
            copy.setTitle("新文档");
    
            System.out.println(template);
            System.out.println(copy);
        }
    }

    适用场景

  • 对象创建成本高

  • 需要大量创建相似对象

  • 希望保留对象当前状态后再复制

四、结构型模式

结构型模式关注类和对象如何组合。它们的目标是让系统结构更加清晰,降低模块之间的耦合。


6. 适配器模式

定义

适配器模式把一个类的接口转换成客户端期望的另一个接口,使原本接口不兼容的类可以一起工作。

方便理解

手机充电器就是适配器。插座提供的是一种接口,手机需要的是另一种接口,充电器负责转换。

代码示例

class OldPayment {
    public void oldPay() {
        System.out.println("调用旧支付接口");
    }
}

interface NewPayment {
    void pay();
}

class PaymentAdapter implements NewPayment {
    private final OldPayment oldPayment;

    public PaymentAdapter(OldPayment oldPayment) {
        this.oldPayment = oldPayment;
    }

    @Override
    public void pay() {
        oldPayment.oldPay();
    }
}

class AdapterDemo {
    public static void main(String[] args) {
        NewPayment payment = new PaymentAdapter(new OldPayment());
        payment.pay();
    }
}

适用场景

  • 新旧接口不兼容

  • 需要复用已有类,但它的接口不符合当前系统

  • 对接第三方 SDK 或老系统

7. 桥接模式

定义

桥接模式把抽象部分和实现部分分离,使它们可以独立变化。

方便理解

如果有圆形、矩形,又有红色、蓝色,如果用继承组合,会出现红色圆形、蓝色圆形、红色矩形、蓝色矩形等大量类。

桥接模式把「形状」和「颜色」拆开,通过组合连接起来。

代码示例

interface Color {
    String name();
}

class Red implements Color {
    @Override
    public String name() {
        return "红色";
    }
}

class Blue implements Color {
    @Override
    public String name() {
        return "蓝色";
    }
}

abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制" + color.name() + "圆形");
    }
}

class BridgeDemo {
    public static void main(String[] args) {
        Shape shape = new Circle(new Red());
        shape.draw();
    }
}

适用场景

  • 一个类存在多个变化维度

  • 想避免多层继承导致类爆炸

  • 抽象和实现都需要独立扩展

8. 组合模式

定义

组合模式把对象组织成树形结构,用来表示整体和部分的关系,并让客户端可以用统一方式处理单个对象和组合对象。

方便理解

文件系统就是组合模式。文件是单个对象,文件夹是组合对象,但它们都可以被展示、删除、统计大小。

代码示例

interface FileComponent {
    void show();
}

class FileLeaf implements FileComponent {
    private final String name;

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

    @Override
    public void show() {
        System.out.println("文件:" + name);
    }
}

class Folder implements FileComponent {
    private final String name;
    private final java.util.List<FileComponent> children = new java.util.ArrayList<>();

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

    public void add(FileComponent component) {
        children.add(component);
    }

    @Override
    public void show() {
        System.out.println("文件夹:" + name);
        for (FileComponent child : children) {
            child.show();
        }
    }
}

适用场景

  • 数据结构是树形结构

  • 希望统一处理单个对象和组合对象

  • 典型场景包括菜单、组织架构、文件目录

9. 装饰器模式

定义

装饰器模式在不改变原对象结构的情况下,动态地给对象增加新功能。

方便理解

点咖啡时,原味咖啡可以加牛奶、加糖、加奶油。每加一样东西,价格和描述都会变化。

装饰器模式就是一层一层给原对象包装功能。

代码示例

interface Coffee {
    String description();

    double cost();
}

class SimpleCoffee implements Coffee {
    @Override
    public String description() {
        return "原味咖啡";
    }

    @Override
    public double cost() {
        return 10;
    }
}

class MilkDecorator implements Coffee {
    private final Coffee coffee;

    public MilkDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String description() {
        return coffee.description() + " + 牛奶";
    }

    @Override
    public double cost() {
        return coffee.cost() + 2;
    }
}

class DecoratorDemo {
    public static void main(String[] args) {
        Coffee coffee = new MilkDecorator(new SimpleCoffee());
        System.out.println(coffee.description());
        System.out.println(coffee.cost());
    }
}

适用场景

  • 需要动态增强对象功能

  • 不想通过继承增加大量子类

  • 功能可以叠加组合

    10. 外观模式

    定义

    外观模式为复杂子系统提供一个统一的高层接口,让客户端使用起来更简单。

    方便理解

    去餐厅吃饭时,顾客不需要直接找采购、厨师、收银员,只需要和服务员沟通。服务员就是外观对象。

    代码示例

    class VideoFile {
        public void load() {
            System.out.println("加载视频文件");
        }
    }
    
    class Codec {
        public void decode() {
            System.out.println("解码视频");
        }
    }
    
    class Player {
        public void play() {
            System.out.println("播放视频");
        }
    }
    
    class VideoFacade {
        private final VideoFile videoFile = new VideoFile();
        private final Codec codec = new Codec();
        private final Player player = new Player();
    
        public void playVideo() {
            videoFile.load();
            codec.decode();
            player.play();
        }
    }

    适用场景

  • 子系统复杂,调用步骤多

  • 希望给外部提供简单入口

  • 降低客户端和多个子系统之间的耦合

11. 享元模式

定义

享元模式通过共享大量细粒度对象,减少内存占用。

方便理解

如果游戏中有一万棵树,每棵树的树种、颜色、纹理可能相同,只有坐标不同。相同的树种信息可以共享,坐标作为外部数据传入。

代码示例

class TreeType {
    private final String name;
    private final String color;

    public TreeType(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public void draw(int x, int y) {
        System.out.println("绘制" + color + name + ",坐标:" + x + "," + y);
    }
}

class TreeFactory {
    private static final java.util.Map<String, TreeType> CACHE = new java.util.HashMap<>();

    public static TreeType getTreeType(String name, String color) {
        String key = name + "_" + color;
        if (!CACHE.containsKey(key)) {
            CACHE.put(key, new TreeType(name, color));
        }
        return CACHE.get(key);
    }
}

class FlyweightDemo {
    public static void main(String[] args) {
        TreeType treeType = TreeFactory.getTreeType("松树", "绿色");
        treeType.draw(10, 20);
        treeType.draw(30, 40);
    }
}

适用场景

  • 系统中有大量相似对象

  • 对象中有可共享的内部状态

  • 需要降低内存占用

    12. 代理模式

    定义

    代理模式为真实对象提供一个代理对象,由代理对象控制对真实对象的访问。

    方便理解

    租房时你可以直接找房东,也可以找中介。中介不是真正的房东,但它可以帮你处理看房、沟通、签约等事情。

    代码示例

    interface Image {
        void display();
    }
    
    class RealImage implements Image {
        private final String fileName;
    
        public RealImage(String fileName) {
            this.fileName = fileName;
            loadFromDisk();
        }
    
        private void loadFromDisk() {
            System.out.println("从磁盘加载图片:" + fileName);
        }
    
        @Override
        public void display() {
            System.out.println("显示图片:" + fileName);
        }
    }
    
    class ImageProxy implements Image {
        private final String fileName;
        private RealImage realImage;
    
        public ImageProxy(String fileName) {
            this.fileName = fileName;
        }
    
        @Override
        public void display() {
            if (realImage == null) {
                realImage = new RealImage(fileName);
            }
            realImage.display();
        }
    }

适用场景

  • 延迟加载

  • 权限控制

  • 日志记录

  • 远程代理

  • Spring AOP 动态代理


五、行为型模式

行为型模式关注对象之间如何分配职责、如何通信、如何协作完成任务。


13. 模板方法模式

定义

模板方法模式在父类中定义算法流程,把部分可变步骤延迟到子类实现。

方便理解

泡茶和泡咖啡流程类似:烧水、冲泡、倒入杯子、加调料。流程固定,细节不同。

代码示例

abstract class Beverage {
    public final void make() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    private void boilWater() {
        System.out.println("烧水");
    }

    private void pourInCup() {
        System.out.println("倒入杯子");
    }

    protected abstract void brew();

    protected abstract void addCondiments();
}

class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("冲泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("加入柠檬");
    }
}

适用场景

  • 多个类流程相同,但部分步骤不同

  • 父类控制流程,子类实现细节

  • 需要复用公共流程代码

14. 策略模式

定义

策略模式把一组算法分别封装起来,使它们可以相互替换。

方便理解

电商优惠策略可以有满减、打折、无优惠。下单时选择不同策略,价格计算方式就不同。

代码示例

interface DiscountStrategy {
    double calculate(double price);
}

class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public double calculate(double price) {
        return price;
    }
}

class PercentDiscountStrategy implements DiscountStrategy {
    @Override
    public double calculate(double price) {
        return price * 0.8;
    }
}

class OrderService {
    private DiscountStrategy discountStrategy;

    public OrderService(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double getFinalPrice(double price) {
        return discountStrategy.calculate(price);
    }
}

适用场景

  • 同一类问题有多种算法

  • 需要在运行时切换算法

  • 想减少大量 if else 策略判断

    15. 命令模式

    定义

    命令模式把请求封装成对象,使请求发送者和请求执行者解耦。

    方便理解

    遥控器按钮就是命令模式。按钮不关心电视怎么开机,只负责触发一个「开机命令」。

    代码示例

    interface Command {
        void execute();
    }
    
    class Light {
        public void on() {
            System.out.println("开灯");
        }
    }
    
    class LightOnCommand implements Command {
        private final Light light;
    
        public LightOnCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.on();
        }
    }
    
    class RemoteControl {
        private Command command;
    
        public void setCommand(Command command) {
            this.command = command;
        }
    
        public void pressButton() {
            command.execute();
        }
    }

    适用场景

  • 请求发送者和执行者需要解耦

  • 需要支持撤销、重做

  • 需要把操作排队、记录日志或延迟执行

16. 职责链模式

定义

职责链模式让多个处理者形成一条链,请求沿着链传递,直到某个处理者处理它。

方便理解

请假审批就是职责链。1 天主管批,3 天经理批,7 天总监批。

代码示例

abstract class Approver {
    protected Approver next;

    public void setNext(Approver next) {
        this.next = next;
    }

    public abstract void approve(int days);
}

class Manager extends Approver {
    @Override
    public void approve(int days) {
        if (days <= 3) {
            System.out.println("经理审批通过");
        } else if (next != null) {
            next.approve(days);
        }
    }
}

class Director extends Approver {
    @Override
    public void approve(int days) {
        if (days <= 7) {
            System.out.println("总监审批通过");
        } else {
            System.out.println("请假天数过长,无法审批");
        }
    }
}

class ChainDemo {
    public static void main(String[] args) {
        Approver manager = new Manager();
        Approver director = new Director();
        manager.setNext(director);

        manager.approve(5);
    }
}

适用场景

  • 一个请求可能由多个对象处理

  • 处理者顺序可以灵活配置

  • 需要避免请求发送者直接依赖具体处理者

    17. 状态模式

    定义

    状态模式把对象在不同状态下的行为封装成不同状态类,使对象行为可以随着状态变化而变化。

    方便理解

    订单有待支付、已支付、已发货。调用同一个 pay() 方法,在不同状态下结果不同。

    代码示例

    interface OrderState {
        void pay(Order order);
    
        void ship(Order order);
    }
    
    class PendingPaymentState implements OrderState {
        @Override
        public void pay(Order order) {
            System.out.println("支付成功");
            order.setState(new PaidState());
        }
    
        @Override
        public void ship(Order order) {
            System.out.println("未支付,不能发货");
        }
    }
    
    class PaidState implements OrderState {
        @Override
        public void pay(Order order) {
            System.out.println("不能重复支付");
        }
    
        @Override
        public void ship(Order order) {
            System.out.println("发货成功");
        }
    }
    
    class Order {
        private OrderState state = new PendingPaymentState();
    
        public void setState(OrderState state) {
            this.state = state;
        }
    
        public void pay() {
            state.pay(this);
        }
    
        public void ship() {
            state.ship(this);
        }
    }

    适用场景

  • 对象有多种状态

  • 同一个操作在不同状态下行为不同

  • 类中存在大量状态判断

18. 观察者模式

定义

观察者模式定义对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知。

方便理解

公众号发布文章后,所有订阅用户都会收到消息。公众号是被观察者,用户是观察者。

代码示例

interface Observer {
    void update(String message);
}

class User implements Observer {
    private final String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + " 收到消息:" + message);
    }
}

class Subject {
    private final java.util.List<Observer> observers = new java.util.ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

适用场景

  • 一个对象变化,需要通知多个对象

  • 事件监听

  • 消息订阅

  • GUI 事件机制

    19. 中介者模式

    定义

    中介者模式用一个中介对象封装多个对象之间的交互,降低对象之间的直接依赖。

    方便理解

    聊天室就是中介者。用户之间不需要直接互相发送消息,而是都通过聊天室转发。

    代码示例

    class ChatRoom {
        public void sendMessage(User user, String message) {
            System.out.println(user.getName() + " 发送消息:" + message);
        }
    }
    
    class User {
        private final String name;
        private final ChatRoom chatRoom;
    
        public User(String name, ChatRoom chatRoom) {
            this.name = name;
            this.chatRoom = chatRoom;
        }
    
        public String getName() {
            return name;
        }
    
        public void send(String message) {
            chatRoom.sendMessage(this, message);
        }
    }

    适用场景

  • 多个对象之间关系复杂

  • 对象之间存在网状调用

  • 希望通过一个中心对象统一协调交互

20. 备忘录模式

定义

备忘录模式在不破坏对象封装性的前提下,保存对象的某个历史状态,以便之后恢复。

方便理解

文本编辑器的撤销功能就是备忘录模式。每次修改前保存一个状态,需要撤销时恢复旧状态。

代码示例

class EditorMemento {
    private final String content;

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

    public String getContent() {
        return content;
    }
}

class Editor {
    private String content;

    public void setContent(String content) {
        this.content = content;
    }

    public EditorMemento save() {
        return new EditorMemento(content);
    }

    public void restore(EditorMemento memento) {
        this.content = memento.getContent();
    }

    public void show() {
        System.out.println(content);
    }
}

适用场景

  • 需要撤销、回滚

  • 需要保存对象历史状态

  • 不希望暴露对象内部实现细节

    21. 迭代器模式

    定义

    迭代器模式提供一种顺序访问集合元素的方法,而不暴露集合的内部结构。

    方便理解

    遍历集合时,我们只关心有没有下一个元素、下一个元素是什么,不需要关心底层是数组、链表还是树。

    代码示例

    interface Iterator<T> {
        boolean hasNext();
    
        T next();
    }
    
    class BookShelf {
        private final java.util.List<String> books = new java.util.ArrayList<>();
    
        public void addBook(String book) {
            books.add(book);
        }
    
        public Iterator<String> iterator() {
            return new BookIterator();
        }
    
        private class BookIterator implements Iterator<String> {
            private int index = 0;
    
            @Override
            public boolean hasNext() {
                return index < books.size();
            }
    
            @Override
            public String next() {
                return books.get(index++);
            }
        }
    }

    适用场景

  • 需要遍历集合对象

  • 不想暴露集合内部结构

  • 希望统一不同集合的遍历方式

22. 访问者模式

定义

访问者模式把作用于某种对象结构中的操作封装到访问者中,使我们可以在不改变对象结构的情况下新增操作。

方便理解

一组图形对象有圆形和矩形。今天要计算面积,明天要导出 XML。如果把所有操作都写进图形类,类会越来越臃肿。访问者模式把这些操作单独拆出来。

代码示例

interface ShapeElement {
    void accept(ShapeVisitor visitor);
}

class CircleElement implements ShapeElement {
    @Override
    public void accept(ShapeVisitor visitor) {
        visitor.visit(this);
    }
}

class RectangleElement implements ShapeElement {
    @Override
    public void accept(ShapeVisitor visitor) {
        visitor.visit(this);
    }
}

interface ShapeVisitor {
    void visit(CircleElement circle);

    void visit(RectangleElement rectangle);
}

class ExportVisitor implements ShapeVisitor {
    @Override
    public void visit(CircleElement circle) {
        System.out.println("导出圆形");
    }

    @Override
    public void visit(RectangleElement rectangle) {
        System.out.println("导出矩形");
    }
}

适用场景

  • 对象结构稳定,但操作经常变化

  • 需要给一组对象新增多个不同操作

  • 希望把数据结构和操作逻辑分离

23. 解释器模式

定义

解释器模式为某种语言或表达式定义语法表示,并提供解释执行的方法。

方便理解

计算器解析表达式、SQL 解析器、规则引擎都和解释器模式有关系。它适合解决特定语法规则的解释问题。

代码示例

interface Expression {
    int interpret();
}

class NumberExpression implements Expression {
    private final int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return number;
    }
}

class AddExpression implements Expression {
    private final Expression left;
    private final Expression right;

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

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

class InterpreterDemo {
    public static void main(String[] args) {
        Expression expression = new AddExpression(
                new NumberExpression(1),
                new NumberExpression(2)
        );

        System.out.println(expression.interpret());
    }
}

适用场景

  • 有固定语法规则

  • 需要解释表达式或规则

  • 典型场景包括计算器、规则引擎、脚本解释器

六、容易混淆的模式对比

1. 工厂方法模式和抽象工厂模式

对比点工厂方法模式抽象工厂模式
创建对象数量通常创建一个产品创建一组相关产品
关注点单个产品的扩展产品族的扩展
例子创建 Windows 按钮或 Mac 按钮创建一整套浅色 UI 或深色 UI

2. 策略模式和状态模式

对比点策略模式状态模式
核心替换算法状态切换
变化来源外部主动选择策略对象内部状态变化
例子满减、打折、无优惠待支付、已支付、已发货

3. 装饰器模式和代理模式

对比点装饰器模式代理模式
核心增强功能控制访问
关系可以层层包装通常代理一个真实对象
例子咖啡加牛奶、加糖图片懒加载、权限代理

4. 模板方法模式和策略模式

对比点模板方法模式策略模式
实现方式继承组合
核心固定流程,改变步骤替换算法
例子泡茶和泡咖啡流程固定选择不同折扣算法

七、学习顺序建议

如果刚开始学习设计模式,不建议一口气死记 23 种,可以按照下面顺序学习:

  • 先学最常用的模式:单例、工厂、策略、模板方法、观察者、代理、装饰器

  • 再学结构相关模式:适配器、外观、组合、桥接

  • 最后学相对复杂或使用频率较低的模式:访问者、解释器、备忘录、享元

八、总结

23 种设计模式可以按照三大类来记忆:

类型记忆重点
创建型模式解决对象创建问题
结构型模式解决对象组合问题
行为型模式解决对象协作问题

实际开发中,不需要为了使用设计模式而使用设计模式。设计模式的价值在于:

  • 降低代码耦合

  • 提高扩展性

  • 提高代码复用性

  • 让复杂逻辑更容易维护

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐