别背23种设计模式,掌握8个就够了

0 阅读12分钟

设计模式不是"银弹",是"经验包"

在学设计模式之前要明白它到底是什么?刚入行的时候我会这么觉得:

  1. 代码炫技的工具
  2. 写代码的必须步骤
  3. 衡量技术水平的标准

直到我在真实项目里踩了无数坑,被过度设计的代码折磨到崩溃,才明白一件事: 很多人不是在用设计模式,而是在折磨自己、折磨团队。

百度是这么介绍设计模式的:

image.png

我想为此添加一句话:设计模式应该是解决方案,而不是目标。

单开里依接迪合

认识各种模式前,我们应该了解它的原则。设计模式的7大原则是所有模式背后的核心思想

如果实在背不熟这7大原则及其定义,至少要熟记单一职责和开闭原则。

  1. 单一职责原则:一个类只做一件事,就像快递员只负责送快递。
  2. 开闭原则:对扩展开放,对修改关闭,就像装修房子可以自由发挥,但不能拆承重墙。
  3. 里氏替换原则:子类可以替换父类,就像可口可乐可以替代水。
  4. 依赖倒置原则:依赖抽象不依赖具体,就像插座不依赖具体电器。
  5. 接口隔离原则:不要依赖不需要的接口,就像你只需点餐,不用洗碗炒菜。
  6. 迪米特法则:只和直接朋友交流,不要和陌生人说话,就像你只和卖家交流,不用管进货渠道。
  7. 合成复用原则:优先使用组合而非继承,就像组装电脑自己选配件。

别背23种设计模式,掌握8个就够了

设计模式看似很多,实际也不少[旺柴]。但是我们也不需要死记硬背,按照以下的方法会轻松很多~

image.png

当我们需要设计问题时,不要先想"用什么模式",先按顺序思考:

  1. 你在解决什么类型的问题?
  2. 需要解耦什么?
  3. 哪些部分可能变化?需要隔离变化吗?
  4. 需求稳定性如何?
  5. 团队熟悉度如何?

1.需要创建对象/需要对象组合结构/需要对象交互,因此也按照创建型/组合型/行为型的方式分类。

2.举例几个常见的解耦结果,我需要创建对象/我的接口不兼容另外一个接口/我希望拓展一个新功能且不影响原来功能/我希望更改一个状态能影响其他状态,对应的是工厂模式/适配器模式/装饰器模式/状态模式

3.根据变化的部分选择模式,如需要频繁切换数据库连接方式/需要切换支付方式/需要根据订单的状态决定对应逻辑,分别对应工厂模式型(创建对象的方式都改变了)/策略模式(不同支付方式不同逻辑,属于业务变了)/状态模式。

4.需求稳定则直接实现,需求频繁变化选择引入模式。人话就是静态和动态配置。

5.团队熟悉可以用复杂模式, 团队不熟悉优先用简单方案,如观察者模式与责任链模式相似,但前者简单,后者稍微复杂一些。

让我们看看具体的设计模式~

建造者模式

  • 分类:创建型模式
  • 解决什么问题:当对象有多个可选参数,且需要保证构建过程的稳定性时。
  • 核心思想:将复杂对象的构建与表示分离。
  • 典型场景:订单构建、配置对象、SQL查询构建。
  • 使用判断准则:当可选参数大于4个时推荐使用,反之则酌情使用。
// 不使用建造者:参数顺序混乱,可读性差
Order order = new Order("123", 99.99, "SUMMER20", Arrays.asList("T恤", "牛仔裤"), LocalDateTime.now());

// 使用建造者:链式调用,清晰易读
Order order = Order.builder()
    .orderId("123")
    .amount(99.99)
    .discountCode("SUMMER20")
    .items(Arrays.asList("T恤", "牛仔裤"))
    .build();

工厂方法

  • 分类:创建型模式
  • 解决什么问题:将对象创建逻辑封装起来,调用方不依赖具体类。
  • 核心思想:定义创建对象的接口,让子类决定实例化哪个类。
  • 典型场景:支付方式工厂、日志框架工厂、数据库连接工厂。
  • 使用判断准则:当创建对象逻辑复杂时,内部有多个实现时推荐使用,反之则酌情使用。
// 支付接口
public interface Payment {
    void pay(BigDecimal amount);
}

// 具体支付实现
public class AlipayPayment implements Payment {
    @Override
    public void pay(BigDecimal amount) {
        // 支付宝支付逻辑
    }
}

// 工厂类
public class PaymentFactory {
    public static Payment createPayment(String type) {
        if ("alipay".equals(type)) {
            return new AlipayPayment();
        }
        // 可以扩展其他支付方式
        throw new IllegalArgumentException("Unsupported payment type");
    }
}

// 使用
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(new BigDecimal("99.99"));

适配器模式

  • 分类:结构型模式
  • 解决什么问题:让接口不兼容的类能够协同工作
  • 核心思想:将一个类的接口转换成客户端期望的另一个接口
  • 典型场景:第三方API对接、旧系统升级、接口标准化
  • 使用判断准则:接口不兼容的万能解,若接口原本就兼容则无需使用。
// 第三方支付接口(无法修改)
public class ThirdPartyPayment {
    public void makePayment(String account, double amount) {
        // 第三方支付逻辑
    }
}

// 我们期望的支付接口
public interface Payment {
    void pay(BigDecimal amount);
}

// 适配器
public class PaymentAdapter implements Payment {
    private ThirdPartyPayment thirdPartyPayment;
    
    public PaymentAdapter(ThirdPartyPayment thirdPartyPayment) {
        this.thirdPartyPayment = thirdPartyPayment;
    }
    
    @Override
    public void pay(BigDecimal amount) {
        thirdPartyPayment.makePayment("default_account", amount.doubleValue());
    }
}

// 使用
Payment payment = new PaymentAdapter(new ThirdPartyPayment());
payment.pay(new BigDecimal("99.99"));

装饰器模式

  • 分类:结构型模式
  • 解决什么问题:在不修改原类的情况下,动态给对象添加功能。
  • 核心思想:通过组合而非继承来扩展功能。
  • 典型场景:IO流包装、日志增强、权限控制、缓存。
  • 使用判断准则:添加新功能的时候是否希望修改原类
// 基础组件
public interface TextComponent {
    String getText();
}

public class PlainText implements TextComponent {
    private String text;
    
    public PlainText(String text) {
        this.text = text;
    }
    
    @Override
    public String getText() {
        return text;
    }
}

// 装饰器:添加加密功能
public class EncryptedText implements TextComponent {
    private TextComponent component;
    
    public EncryptedText(TextComponent component) {
        this.component = component;
    }
    
    @Override
    public String getText() {
        return encrypt(component.getText());
    }
    
    private String encrypt(String text) {
        // 加密逻辑
        return "ENCRYPTED:" + text;
    }
}

// 装饰器:添加压缩功能
public class CompressedText implements TextComponent {
    private TextComponent component;
    
    public CompressedText(TextComponent component) {
        this.component = component;
    }
    
    @Override
    public String getText() {
        return compress(component.getText());
    }
    
    private String compress(String text) {
        // 压缩逻辑
        return "COMPRESSED:" + text;
    }
}

// 使用:可以任意组合装饰器
TextComponent text = new CompressedText(new EncryptedText(new PlainText("Hello")));
System.out.println(text.getText()); // COMPRESSED:ENCRYPTED:Hello

策略模式

  • 分类:行为型模式
  • 解决什么问题:将不同的算法封装起来,使它们可以互相替换。
  • 核心思想:定义算法族,分别封装,让它们可以互相替换。
  • 典型场景:支付方式、排序算法、折扣计算、验证规则。
  • 使用判断准则:是否有大量if-else,且希望替换
// 策略接口
public interface DiscountStrategy {
    BigDecimal calculate(BigDecimal price);
}

// 具体策略
public class NormalDiscount implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price;
    }
}

public class VIPDiscount implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.8"));
    }
}

public class SVIPDiscount implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.6"));
    }
}

// 策略工厂
public class DiscountStrategyFactory {
    public static DiscountStrategy getStrategy(String userType) {
        switch (userType) {
            case "vip":
                return new VIPDiscount();
            case "svip":
                return new SVIPDiscount();
            default:
                return new NormalDiscount();
        }
    }
}

// 使用:消除if-else
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy("vip");
BigDecimal finalPrice = strategy.calculate(new BigDecimal("100"));

观察者模式

  • 分类:行为型模式
  • 解决什么问题:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖它的对象都会收到通知。
  • 核心思想:发布-订阅机制。
  • 典型场景:消息推送、事件监听、GUI事件处理、Spring事件机制。
  • 使用判断准则:是否需要一对多的通知行为
// 观察者接口
public interface Observer {
    void update(String message);
}

// 被观察者
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体被观察者:订单
public class Order implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String status;
    
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update("订单状态变更为:" + status);
        }
    }
    
    public void setStatus(String status) {
        this.status = status;
        notifyObservers();
    }
}

// 具体观察者:邮件通知
public class EmailNotifier implements Observer {
    @Override
    public void update(String message) {
        System.out.println("发送邮件通知:" + message);
    }
}

// 具体观察者:短信通知
public class SMSNotifier implements Observer {
    @Override
    public void update(String message) {
        System.out.println("发送短信通知:" + message);
    }
}

// 使用
Order order = new Order();
order.registerObserver(new EmailNotifier());
order.registerObserver(new SMSNotifier());
order.setStatus("已支付"); // 所有观察者都会收到通知

状态模式

  • 分类:行为型模式
  • 解决什么问题:允许一个对象在其内部状态改变时改变它的行为。
  • 核心思想:状态决定行为。
  • 典型场景:订单状态流转、工作流、游戏角色状态。
  • 使用判断准则:状态数量多,且不同状态有不同逻辑
// 状态接口
public interface OrderState {
    void handle(Order order);
}

// 具体状态:待支付
public class PendingPaymentState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("处理待支付状态");
        order.setState(new PaidState());
    }
}

// 具体状态:已支付
public class PaidState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("处理已支付状态");
        order.setState(new ShippedState());
    }
}

// 具体状态:已发货
public class ShippedState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("处理已发货状态");
        order.setState(new CompletedState());
    }
}

// 具体状态:已完成
public class CompletedState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("订单已完成");
    }
}

// 订单上下文
public class Order {
    private OrderState state;
    
    public Order() {
        this.state = new PendingPaymentState();
    }
    
    public void setState(OrderState state) {
        this.state = state;
    }
    
    public void process() {
        state.handle(this);
    }
}

// 使用
Order order = new Order();
order.process(); // 待支付 → 已支付
order.process(); // 已支付 → 已发货
order.process(); // 已发货 → 已完成
order.process(); // 已完成

职责链模式

  • 分类:行为型模式
  • 解决什么问题:将请求的发送者和接收者解耦,让多个对象都有机会处理请求。
  • 核心思想:形成一条处理链,请求沿着链传递,直到被处理。
  • 典型场景:请假审批、Filter链、异常处理、工作流。
  • 使用判断准则:有多个对象可以处理请求,需要动态指定处理顺序
// 处理器接口
public interface Handler {
    void handleRequest(Request request);
    void setNextHandler(Handler handler);
}

// 抽象处理器
public abstract class AbstractHandler implements Handler {
    private Handler nextHandler;
    
    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
    
    @Override
    public void handleRequest(Request request) {
        if (canHandle(request)) {
            doHandle(request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            System.out.println("无人处理该请求");
        }
    }
    
    protected abstract boolean canHandle(Request request);
    protected abstract void doHandle(Request request);
}

// 具体处理器:组长
public class TeamLeaderHandler extends AbstractHandler {
    @Override
    protected boolean canHandle(Request request) {
        return request.getDays() <= 3;
    }
    
    @Override
    protected void doHandle(Request request) {
        System.out.println("组长审批:批准" + request.getDays() + "天假期");
    }
}

// 具体处理器:经理
public class ManagerHandler extends AbstractHandler {
    @Override
    protected boolean canHandle(Request request) {
        return request.getDays() <= 7;
    }
    
    @Override
    protected void doHandle(Request request) {
        System.out.println("经理审批:批准" + request.getDays() + "天假期");
    }
}

// 具体处理器:总监
public class DirectorHandler extends AbstractHandler {
    @Override
    protected boolean canHandle(Request request) {
        return request.getDays() > 7;
    }
    
    @Override
    protected void doHandle(Request request) {
        System.out.println("总监审批:批准" + request.getDays() + "天假期");
    }
}

// 请求对象
public class Request {
    private int days;
    
    public Request(int days) {
        this.days = days;
    }
    
    public int getDays() {
        return days;
    }
}

// 使用
Handler teamLeader = new TeamLeaderHandler();
Handler manager = new ManagerHandler();
Handler director = new DirectorHandler();

teamLeader.setNextHandler(manager);
manager.setNextHandler(director);

teamLeader.handleRequest(new Request(2));  // 组长审批
teamLeader.handleRequest(new Request(5));  // 经理审批
teamLeader.handleRequest(new Request(10)); // 总监审批

易混淆模式速查表

23种模式中,也有一些比较相似的,这个时候我们可以按照我们具体需求选择对应的模式。

策略模式 vs 状态模式

对比项策略模式状态模式
目的封装算法封装状态
切换方式客户端主动切换状态自动转换
关注点行为替换状态转换
典型场景支付方式、排序算法订单状态流转、工作流
一句话区分策略是"选一个"状态是"流转起来"

装饰器模式 vs 适配器模式

对比项装饰器模式适配器模式
目的动态增强功能转换接口
是否改变接口否,保持原接口是,转换成客户端期望的接口
是否改变功能是,添加新功能否,功能本质不变
是否可组合可以多层组合不可组合(一对一适配)
典型场景IO流包装、日志增强第三方API对接、旧系统兼容
一句话区分装饰器是"增强功能"适配器是"转换接口"

工厂方法 vs 抽象工厂

对比项工厂方法抽象工厂
目的创建一种产品创建产品族
层级一层抽象两层抽象
扩展性新增产品需新增工厂新增产品族需新增工厂
典型场景支付方式工厂UI组件库(按钮+文本框)
一句话区分工厂方法造"一个东西"抽象工厂造"一套东西"

常见错误操作

为了避免我们写出错误的设计模式,我们应该多看看别人的错误案例。

1. 为模式而模式 🔥🔥🔥

// ❌ 简单支付用两层工厂
public class PaymentFactory {
    public Payment create(String type) {
        if ("alipay".equals(type)) {
            return new AlipayFactory().create(); // 多余的嵌套
        }
    }
}

2. 过早抽象 🔥🔥

// ❌ 未来可能支持4种支付,现在只用到1种
class CreditCardPayment implements PaymentStrategy {...}
class PayPalPayment implements PaymentStrategy {...} // 从未使用
class BitcoinPayment implements PaymentStrategy {...} // 从未使用

3. 模式堆砌 🔥

// ❌ 一个模块用>2种模式,加功能改>3个文件
// 组合了工厂+策略+装饰器,只为一个简单功能
public class ComplexPayment {
    // 工厂创建策略
    private PaymentStrategy strategy = StrategyFactory.create("vip");
    // 装饰器包装
    private PaymentDecorator decorated = new LoggedPayment(strategy);
    // 只为了一个简单支付调用
    public void pay(BigDecimal amount) {
        decorated.pay(amount);
    }
}

4. 全局污染 🔥🔥🔥

// ❌ 所有服务都搞单例,测试时无法隔离
public class UserService {
    private static UserService instance;
    private UserService() {}
    public static UserService getInstance() {...}
}

5. 局部优化 🔥

// ❌ 只有3个状态,硬上状态模式
// 用if-else或状态表驱动更简单
public class OrderState {
    public interface State { void handle(); }
    public class PendingState implements State { ... }
    public class PaidState implements State { ... }
    public class ShippedState implements State { ... }
    // 3个状态搞了3个类,反而不如if-else清晰
}

设计模式不是银弹,而是权衡

我的5条极简原则(建议熟记):

  1. 能直白就不抽象:直白的代码可能不够"优雅",但一定更好维护。
  2. 能少一层就不多一层:每多一层封装,就多一份认知成本。
  3. 新人能快速看懂,才叫好代码:代码是写给人看的,顺便给机器执行。
  4. 先满足业务,再谈优雅:业务都没跑通,优雅给谁看?
  5. 可维护 > 可装逼:这句话最难,但也最重要。真正的专业,是知道什么时候不用什么。

简单来说,好的代码就是简单易读,能扛业务。

如果这篇文章对你有帮助,点个赞收藏一下吧。有问题欢迎评论区交流~