设计模式

欢迎来到第十四阶段——高级专题与分布式。前面阶段我们学了语言机制、工程化、Web 框架。这一阶段我们拔高——设计模式、数据结构算法、Redis、消息队列、微服务、Docker,让你从”会用框架”到”能设计架构”。第一站——设计模式

设计模式(Design Pattern)是前辈经验的总结——面对特定问题时,“标准答案”长什么样。GoF(Gang of Four)23 种模式是经典。这一章我们看六大设计原则、三大类模式、Java 标准库里的实例。

一、六大设计原则

设计模式的根基是设计原则——遵循原则才能写出好代码,模式只是原则的具体应用。

1.1 SOLID 五原则

原则全称含义
S - 单一职责Single Responsibility一个类只有一个变化的原因
O - 开闭原则Open-Closed对扩展开放,对修改关闭
L - 里氏替换Liskov Substitution子类能完全替换父类
I - 接口隔离Interface Segregation接口小而专,不要胖接口
D - 依赖倒置Dependency Inversion依赖抽象不依赖具体

单一职责(SRP) —— 一个类只干一件事。UserService 不该既管用户认证又管发邮件——拆成 UserServiceEmailService

开闭原则(OCP) —— 加新功能不改老代码。比如策略模式——加新策略就新增类,不改 Context

里氏替换(LSP) —— 子类不能违反父类约定。父类 add(a, b) 返回 a+b,子类重写返回 a-b 就违反 LSP——用父类的地方换成子类会出错。

接口隔离(ISP) —— 接口要小。一个 UserService 接口里既有读方法又有写方法,读客户端被迫依赖写方法——拆成 UserReaderUserWriter

依赖倒置(DIP) —— 高层模块不依赖低层模块,都依赖抽象。UserService(高层)不直接依赖 UserRepositoryImpl(低层),依赖 UserRepository 接口——这就是 Spring IoC 的思想。

1.2 迪米特法则(LoD)

迪米特法则(Law of Demeter)——最少知识原则。一个对象只跟”朋友”说话,不跟”陌生人”说话。

// 违反 LoD: 跟陌生人的陌生人说话
order.getCustomer().getAddress().getCity();

// 遵守 LoD: 让直接朋友帮忙
order.getCustomerCity();

不熟的对象别深挖——只调直接依赖对象的方法。降低耦合。

二、创建型模式

创建型模式关注”怎么创建对象”——把创建和使用解耦。

2.1 单例(Singleton)

保证一个类只有一个实例。Java 标准库里 Runtime.getRuntime() 就是单例。

// 枚举单例 (最佳实践, 防反射防序列化)
public enum Singleton {
    INSTANCE;
    public void doSomething() { ... }
}

// 双重检查锁 (经典写法)
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;
    }
}

volatile 必加——防止指令重排导致的”半初始化对象泄漏”。

2.2 工厂方法(Factory Method)

定义创建对象的接口,让子类决定实例化哪个类。

interface Product { void use(); }
class ProductA implements Product { public void use() { System.out.println("用 A"); } }
class ProductB implements Product { public void use() { System.out.println("用 B"); } }

abstract class Factory {
    abstract Product create();
}
class FactoryA extends Factory { Product create() { return new ProductA(); } }
class FactoryB extends Factory { Product create() { return new ProductB(); } }

// 用
Factory f = new FactoryA();
Product p = f.create();   // ProductA

Spring 的 BeanFactory 就是工厂模式——getBean(name) 返回 Bean 实例。

2.3 建造者(Builder)

把复杂对象的构造和表示分离——一步步构建。

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

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

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

        public Builder name(String n) { this.name = n; return this; }
        public Builder age(int a) { this.age = a; return this; }
        public Builder email(String e) { this.email = e; return this; }
        public Builder address(String a) { this.address = a; return this; }
        public User build() { return new User(this); }
    }
}

// 用
User u = new User.Builder()
    .name("张三").age(20).email("a@b.com").build();

Lombok 的 @Builder 自动生成这些。StringBuilder/StringBuilder 也是 Builder 模式。

2.4 原型(Prototype)

通过克隆现有对象创建新对象——实现 Cloneable 接口。

public class Prototype implements Cloneable {
    private String data;
    public Prototype clone() {
        try { return (Prototype) super.clone(); }
        catch (CloneNotSupportedException e) { throw new RuntimeException(e); }
    }
}

Object.clone() 是浅拷贝——基本类型和引用复制,引用指向的对象不复制。深拷贝要递归克隆或序列化。

三、结构型模式

结构型模式关注”类和对象怎么组合”——适配、装饰、代理。

3.1 适配器(Adapter)

让接口不兼容的类能一起工作——把一个接口转换成另一个。

// 旧接口
interface OldPrinter { void printOld(String s); }
class OldPrinterImpl implements OldPrinter {
    public void printOld(String s) { System.out.println("旧打印: " + s); }
}

// 新接口
interface NewPrinter { void print(String s); }

// 适配器: 把旧接口包装成新接口
class PrinterAdapter implements NewPrinter {
    private OldPrinter old;
    public PrinterAdapter(OldPrinter old) { this.old = old; }
    public void print(String s) { old.printOld(s); }
}

JDK 的 InputStreamReader 是适配器——把 InputStream(字节流)适配成 Reader(字符流)。

3.2 装饰器(Decorator)

动态给对象加功能——比继承更灵活。

interface Coffee { double cost(); }
class SimpleCoffee implements Coffee {
    public double cost() { return 10; }
}

// 装饰器: 加奶
class MilkDecorator implements Coffee {
    private Coffee coffee;
    public MilkDecorator(Coffee c) { this.coffee = c; }
    public double cost() { return coffee.cost() + 2; }
}
// 装饰器: 加糖
class SugarDecorator implements Coffee {
    private Coffee coffee;
    public SugarDecorator(Coffee c) { this.coffee = c; }
    public double cost() { return coffee.cost() + 1; }
}

// 用
Coffee c = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
c.cost();   // 10 + 2 + 1 = 13

JDK 的 BufferedReader/DataInputStream 都是装饰器——给 InputStream 加缓冲、加类型读写。

3.3 代理(Proxy)

给对象加个代理,控制访问。第十阶段的动态代理就是它的应用。

interface Service { void execute(); }
class RealService implements Service {
    public void execute() { System.out.println("执行"); }
}
class ProxyService implements Service {
    private RealService real;
    public void execute() {
        if (real == null) real = new RealService();
        System.out.println("[前置]");
        real.execute();
        System.out.println("[后置]");
    }
}

3.4 外观(Facade)

给复杂子系统一个统一入口——简化调用。

class CPU { void start() { System.out.println("CPU 启动"); } }
class Memory { void load() { System.out.println("内存加载"); } }
class Disk { void read() { System.out.println("硬盘读取"); } }

class ComputerFacade {
    private CPU cpu = new CPU();
    private Memory memory = new Memory();
    private Disk disk = new Disk();

    public void start() {
        cpu.start();
        memory.load();
        disk.read();
        System.out.println("电脑启动完成");
    }
}

// 用
new ComputerFacade().start();   // 一行搞定, 不用关心内部

Spring 的 JdbcTemplate 就是 Facade——把 JDBC 的复杂操作封装成 query/update 几个方法。

3.5 组合(Composite)

树形结构——统一对待单个对象和组合对象。

interface Component { void display(); }
class Leaf implements Component {
    private String name;
    public Leaf(String n) { name = n; }
    public void display() { System.out.println("叶子: " + name); }
}
class Composite implements Component {
    private List<Component> children = new ArrayList<>();
    private String name;
    public Composite(String n) { name = n; }
    public void add(Component c) { children.add(c); }
    public void display() {
        System.out.println("分支: " + name);
        for (Component c : children) c.display();
    }
}

Swing 的 Container/Component 是组合模式——容器里能放组件也能放容器。

四、行为型模式

行为型模式关注”对象间怎么通信、职责怎么分配”。

4.1 策略(Strategy)

定义一系列算法,封装起来,可互换——避免一堆 if-else。

interface PayStrategy { void pay(double amount); }
class WechatPay implements PayStrategy {
    public void pay(double a) { System.out.println("微信支付 " + a); }
}
class AliPay implements PayStrategy {
    public void pay(double a) { System.out.println("支付宝 " + a); }
}

class PayContext {
    private PayStrategy strategy;
    public PayContext(PayStrategy s) { this.strategy = s; }
    public void checkout(double amount) { strategy.pay(amount); }
}

// 用
new PayContext(new WechatPay()).checkout(99.5);
new PayContext(new AliPay()).checkout(99.5);

加新支付方式——新增 PayStrategy 实现类,不改 PayContext。这就是开闭原则。

4.2 观察者(Observer)

一对多依赖——一个对象状态变化,所有依赖者收到通知。

interface Observer { void update(String event); }
class EmailNotifier implements Observer {
    public void update(String e) { System.out.println("邮件通知: " + e); }
}
class SmsNotifier implements Observer {
    public void update(String e) { System.out.println("短信通知: " + e); }
}

class Subject {
    private List<Observer> observers = new ArrayList<>();
    public void subscribe(Observer o) { observers.add(o); }
    public void notifyAll(String event) {
        for (Observer o : observers) o.update(event);
    }
}

Spring 的 ApplicationEvent/ApplicationListener 是观察者模式。

4.3 模板方法(Template Method)

定义算法骨架,子类重写特定步骤。

abstract class Game {
    public final void play() {   // 模板方法, 骨架固定
        init();
        start();
        end();
    }
    protected abstract void init();
    protected abstract void start();
    protected void end() { System.out.println("游戏结束"); }
}
class Chess extends Game {
    protected void init() { System.out.println("摆棋盘"); }
    protected void start() { System.out.println("下棋"); }
}

AbstractListindexOf 是模板方法——它调用子类实现的 size()/get()

4.4 责任链(Chain of Responsibility)

请求沿链传递,每个处理器决定处理或传给下一个。

abstract class Handler {
    protected Handler next;
    public Handler setNext(Handler n) { this.next = n; return n; }
    public abstract void handle(String request);
}
class AuthHandler extends Handler {
    public void handle(String r) {
        if (r.contains("auth")) System.out.println("认证通过");
        else if (next != null) next.handle(r);
    }
}
class LogHandler extends Handler {
    public void handle(String r) {
        System.out.println("记录日志: " + r);
        if (next != null) next.handle(r);
    }
}

// 用
Handler chain = new AuthHandler();
chain.setNext(new LogHandler());
chain.handle("auth");

Spring 的 FilterChainInterceptor 链都是责任链。

4.5 状态(State)

对象状态变化时,行为也变化——把状态封装成类。

interface State { void handle(); }
class IdleState implements State { public void handle() { System.out.println("空闲"); } }
class BusyState implements State { public void handle() { System.out.println("忙"); } }

class Worker {
    private State state;
    public void setState(State s) { this.state = s; }
    public void work() { state.handle(); }
}

五、Java 标准库中的设计模式

模式JDK 例子
单例Runtime.getRuntime()System
工厂方法Calendar.getInstance()List.of()
抽象工厂DocumentBuilderFactory
建造者StringBuilderLocale.Builder
原型Object.clone()
适配器InputStreamReaderArrays.asList()
装饰器BufferedReaderDataInputStream
代理ProxyMethodInterceptor
外观JdbcTemplateFiles
组合Container/Component(Swing)
策略ComparatorFileFilter
观察者PropertyChangeListener
模板方法AbstractListHttpServlet
责任链FilterChain
状态Thread.State(部分)
迭代器IteratorIterable

设计模式不是”发明”的——它们是对优秀代码的”总结”。JDK 里到处都是。

六、实战:策略 + 工厂重构 if-else

Java · 在线运行

观察重点

  • 策略 + 工厂消除 if-else——加新支付方式只注册不改业务,开闭原则。
  • 装饰器自由组合——Sugar(Milk(Coffee)) 等于”加糖加奶咖啡”。
  • 观察者解耦——下单时通知邮件/库存/积分三个观察者,互不影响。

七、本章小结

类别模式
6 原则SRP/OCP/LSP/ISP/DIP/LoD
创建型单例/工厂/建造者/原型
结构型适配器/装饰器/代理/外观/组合
行为型策略/观察者/模板方法/责任链/状态

记忆口诀

  • SOLID 五原则——单、开、里、接、依。
  • 策略消除 if-else——每分支一个类,工厂统一找。
  • 装饰器比继承灵活——组合优于继承。
  • 观察者一对多——事件解耦。
  • 模板方法定骨架——子类填细节。
  • 责任链串起来——请求一节一节过。

结语:模式是手段不是目的

设计模式是经验的结晶,但别滥用——简单 if-else 三行的逻辑非要上策略模式就是过度设计。模式的本质是”解决特定问题”——遇到问题再看模式,不是拿着模式找问题。下一章看更硬核的——数据结构与算法