设计模式
设计模式是软件设计中常见问题的通用解决方案。它们不是具体的代码,而是一种经过验证的思考方式。理解设计模式,能让你在面对复杂系统时看到本质,在设计接口时更有章法。
关于这份文档
这份设计模式文档侧重于 Java 实现,从面向对象的角度理解模式的核心思想。每个模式都配有可直接运行的完整示例。
如果你正在学习面向对象三大特性(封装、继承、多态),会发现设计模式正是这些特性的综合运用。
模式的分类
设计模式分为三大类:
创建型模式 —— 解决「对象怎么创建」的问题
| 模式 | 核心思想 |
|---|---|
| 单例模式 | 一个类只有一个实例 |
| 工厂模式 | 把创建逻辑封装起来 |
| 建造者模式 | 分步骤构建复杂对象 |
| 原型模式 | 通过克隆创建对象 |
结构型模式 —— 解决「类和对象怎么组合」的问题
| 模式 | 核心思想 |
|---|---|
| 装饰器模式 | 动态给对象添加功能 |
| 适配器模式 | 让不兼容的接口合作 |
| 代理模式 | 通过代理间接访问对象 |
行为型模式 —— 解决「职责怎么分配」的问题
| 模式 | 核心思想 |
|---|---|
| 策略模式 | 可以互换的算法 |
| 观察者模式 | 一对多的依赖通知 |
| 模板方法模式 | 把不变的行为封装起来 |
为什么学习设计模式
没学模式之前: 学了模式之后:
↓ ↓
看到一个复杂系统 → 能识别出模式
不知道怎么组织代码 → 有章可循
听到「策略」「装饰器」→ 知道是什么、为什么
设计被说「不合理」 → 能用模式语言解释常见误区
- 模式不是银弹:不要为了用模式而用模式,简单的 if-else 能解决问题就不必引入模式
- 理解重于记忆:理解模式的意图和适用场景,比记住 UML 图更重要
- 没有唯一答案:同一个问题可能用不同的模式解决,要结合实际情况判断
开始学习
如果你是第一次接触设计模式,建议按这个顺序学习:
- 单例模式 —— 最简单,也最常用
- 工厂模式 —— 创建型模式的基础
- 策略模式 —— 行为型模式的入门
- 装饰器模式 —— 结构型的代表,理解「组合优于继承」
设计模式不是 Java 独有的,但 Java 的面向对象特性和接口机制让大多数模式的实现非常自然。
创建型模式
1. 单例模式
确保一个类只有一个实例,并提供一个全局访问点。
饿汉式
public class Singleton {
// 类加载时创建
private static final Singleton INSTANCE = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return INSTANCE;
}
}懒汉式(线程安全)
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;
}
}枚举方式(推荐)
public enum Singleton {
INSTANCE;
public void method() {
System.out.println("单例方法");
}
}枚举方式是《Effective Java》作者推荐的最佳实现,天然防反射、防序列化。
2. 工厂模式
将对象的创建逻辑集中到一个类中,避免调用方依赖具体类。
简单工厂
public class SimpleFactory {
public static Product create(String type) {
return switch (type) {
case "A" -> new ProductA();
case "B" -> new ProductB();
default -> throw new IllegalArgumentException();
};
}
}工厂方法
public interface Factory {
Product create();
}
public class FactoryA implements Factory {
@Override
public Product create() {
return new ProductA();
}
}抽象工厂
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}3. 建造者模式
当一个类构造参数很多,且大部分可选时,建造者模式比重叠构造器更清晰。
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. 原型模式
通过克隆已有对象来创建新对象,而不是从头构建。
public class Prototype implements Cloneable {
@Override
protected Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
}注意:默认的 clone() 是浅克隆。如果对象中有引用类型字段,需要自行实现深克隆。
结构型模式
5. 装饰器模式
不修改原有类的情况下,动态地给对象添加功能。核心思想是「组合优于继承」。
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 装饰 FileInputStream,DataInputStream 装饰 BufferedInputStream。
6. 适配器模式
让接口不兼容的类能够一起工作。分「类适配器」(继承)和「对象适配器」(组合)两种,后者更灵活。
// 目标接口
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. 代理模式
通过代理对象控制对原对象的访问,常用于延迟加载、访问控制、日志记录。
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. 观察者模式
当一个对象状态变化时,自动通知所有依赖它的对象。也叫「发布-订阅」模式。
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.Observable 和 java.util.Observer,不过已经废弃了,建议自己实现。
9. 策略模式
定义一系列算法,把它们一个个封装起来,使它们可以互相替换。
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 防止骨架被修改。
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);
}
}总结
| 类型 | 模式 | 用途 |
|---|---|---|
| 创建型 | 单例、工厂、建造者、原型 | 对象创建 |
| 结构型 | 装饰器、适配器、代理 | 类/对象组合 |
| 行为型 | 观察者、策略、模板方法 | 职责分配 |
记住:先理解问题,再选模式。模式是工具,不是目的。
