Skip to content

设计模式

设计模式是软件设计中常见问题的通用解决方案。它们不是具体的代码,而是一种经过验证的思考方式。理解设计模式,能让你在面对复杂系统时看到本质,在设计接口时更有章法。

关于这份文档

这份设计模式文档侧重于 Java 实现,从面向对象的角度理解模式的核心思想。每个模式都配有可直接运行的完整示例。

如果你正在学习面向对象三大特性(封装、继承、多态),会发现设计模式正是这些特性的综合运用。

模式的分类

设计模式分为三大类:

创建型模式 —— 解决「对象怎么创建」的问题

模式核心思想
单例模式一个类只有一个实例
工厂模式把创建逻辑封装起来
建造者模式分步骤构建复杂对象
原型模式通过克隆创建对象

结构型模式 —— 解决「类和对象怎么组合」的问题

模式核心思想
装饰器模式动态给对象添加功能
适配器模式让不兼容的接口合作
代理模式通过代理间接访问对象

行为型模式 —— 解决「职责怎么分配」的问题

模式核心思想
策略模式可以互换的算法
观察者模式一对多的依赖通知
模板方法模式把不变的行为封装起来

为什么学习设计模式

没学模式之前:        学了模式之后:
    ↓                    ↓
看到一个复杂系统    →  能识别出模式
不知道怎么组织代码  →  有章可循
听到「策略」「装饰器」→  知道是什么、为什么
设计被说「不合理」  →  能用模式语言解释

常见误区

  • 模式不是银弹:不要为了用模式而用模式,简单的 if-else 能解决问题就不必引入模式
  • 理解重于记忆:理解模式的意图和适用场景,比记住 UML 图更重要
  • 没有唯一答案:同一个问题可能用不同的模式解决,要结合实际情况判断

开始学习

如果你是第一次接触设计模式,建议按这个顺序学习:

  1. 单例模式 —— 最简单,也最常用
  2. 工厂模式 —— 创建型模式的基础
  3. 策略模式 —— 行为型模式的入门
  4. 装饰器模式 —— 结构型的代表,理解「组合优于继承」

设计模式不是 Java 独有的,但 Java 的面向对象特性和接口机制让大多数模式的实现非常自然。

创建型模式

1. 单例模式

确保一个类只有一个实例,并提供一个全局访问点。

饿汉式

java
public class Singleton {
    // 类加载时创建
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() { }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

懒汉式(线程安全)

java
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;
    }
}

枚举方式(推荐)

java
public enum Singleton {
    INSTANCE;

    public void method() {
        System.out.println("单例方法");
    }
}

枚举方式是《Effective Java》作者推荐的最佳实现,天然防反射、防序列化。

2. 工厂模式

将对象的创建逻辑集中到一个类中,避免调用方依赖具体类。

简单工厂

java
public class SimpleFactory {
    public static Product create(String type) {
        return switch (type) {
            case "A" -> new ProductA();
            case "B" -> new ProductB();
            default -> throw new IllegalArgumentException();
        };
    }
}

工厂方法

java
public interface Factory {
    Product create();
}

public class FactoryA implements Factory {
    @Override
    public Product create() {
        return new ProductA();
    }
}

抽象工厂

java
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

3. 建造者模式

当一个类构造参数很多,且大部分可选时,建造者模式比重叠构造器更清晰。

java
public class User {
    private final String name;
    private final int age;
    private final String email;

    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.email = builder.email;
    }

    public static class Builder {
        private String name;
        private int age;
        private String email;

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

        public Builder age(int age) {
            this.age = age;
            return this;
        }

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

        public User build() {
            return new User(this);
        }
    }
}

// 使用
User user = new User.Builder()
    .name("张三")
    .age(25)
    .email("zhang@example.com")
    .build();

4. 原型模式

通过克隆已有对象来创建新对象,而不是从头构建。

java
public class Prototype implements Cloneable {
    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }
}

注意:默认的 clone() 是浅克隆。如果对象中有引用类型字段,需要自行实现深克隆。

结构型模式

5. 装饰器模式

不修改原有类的情况下,动态地给对象添加功能。核心思想是「组合优于继承」。

java
public interface DataSource {
    void write(String data);
    String read();
}

public class FileDataSource implements DataSource {
    @Override
    public void write(String data) { /* 写入文件 */ }
    @Override
    public String read() { return ""; }
}

// 装饰器基类
public class DataSourceDecorator implements DataSource {
    protected DataSource wrappee;

    public DataSourceDecorator(DataSource wrappee) {
        this.wrappee = wrappee;
    }

    @Override
    public void write(String data) { wrappee.write(data); }
    @Override
    public String read() { return wrappee.read(); }
}

// 加密装饰器
public class EncryptionDecorator extends DataSourceDecorator {
    public EncryptionDecorator(DataSource wrappee) {
        super(wrappee);
    }

    @Override
    public void write(String data) {
        super.write(encrypt(data));
    }

    @Override
    public String read() {
        return decrypt(super.read());
    }

    private String encrypt(String data) {
        return Base64.getEncoder().encodeToString(data.getBytes());
    }

    private String decrypt(String data) {
        return new String(Base64.getDecoder().decode(data));
    }
}

Java I/O 类库大量使用了装饰器模式:BufferedInputStream 装饰 FileInputStreamDataInputStream 装饰 BufferedInputStream

6. 适配器模式

让接口不兼容的类能够一起工作。分「类适配器」(继承)和「对象适配器」(组合)两种,后者更灵活。

java
// 目标接口
public interface MediaPlayer {
    void play(String filename);
}

// 被适配者
public class AdvancedMediaPlayer {
    public void playMp4(String filename) {
        System.out.println("Playing MP4: " + filename);
    }
}

// 适配器
public class MediaAdapter implements MediaPlayer {
    private final AdvancedMediaPlayer player = new AdvancedMediaPlayer();

    @Override
    public void play(String filename) {
        if (filename.endsWith("mp4")) {
            player.playMp4(filename);
        }
    }
}

7. 代理模式

通过代理对象控制对原对象的访问,常用于延迟加载、访问控制、日志记录。

java
public interface Image {
    void display();
}

public class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }

    private void loadFromDisk() {
        System.out.println("Loading: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying: " + filename);
    }
}

public class ImageProxy implements Image {
    private RealImage realImage;
    private final String filename;

    public ImageProxy(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);  // 延迟加载
        }
        realImage.display();
    }
}

行为型模式

8. 观察者模式

当一个对象状态变化时,自动通知所有依赖它的对象。也叫「发布-订阅」模式。

java
public interface Observer {
    void update(String message);
}

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

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

    public void detach(Observer observer) {
        observers.remove(observer);
    }

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

JDK 内置了 java.util.Observablejava.util.Observer,不过已经废弃了,建议自己实现。

9. 策略模式

定义一系列算法,把它们一个个封装起来,使它们可以互相替换。

java
public interface PaymentStrategy {
    void pay(int amount);
}

public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("Credit card: " + amount);
    }
}

public class PayPalPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("PayPal: " + amount);
    }
}

public class ShoppingCart {
    private PaymentStrategy strategy;

    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void checkout(int amount) {
        strategy.pay(amount);
    }
}

策略模式和观察者模式是 Java 标准库中最常用的两个行为型模式。

10. 模板方法模式

在父类中定义算法的骨架,把具体步骤延迟到子类中实现。父类用 final 防止骨架被修改。

java
public abstract class DataProcessor {
    // 模板方法
    public final void process() {
        String data = readData();
        String processed = processData(data);
        writeData(processed);
    }

    protected abstract String readData();
    protected abstract String processData(String data);

    protected void writeData(String data) {
        System.out.println("Writing: " + data);
    }
}

总结

类型模式用途
创建型单例、工厂、建造者、原型对象创建
结构型装饰器、适配器、代理类/对象组合
行为型观察者、策略、模板方法职责分配

记住:先理解问题,再选模式。模式是工具,不是目的。

基于 VitePress 构建