吃透设计模式:从原理到落地(如何选型),Java/Spring开发场景

设计模式是软件开发的"通用套路",它不是凭空创造的语法,而是前辈们总结的、解决特定问题的最优实践。本文结合Java/Spring实战场景,从"是什么、怎么用、怎么选"三个维度,把设计模式讲透,让新手也能快速落地。

一、核心认知:设计模式的三大分类(Java视角)

设计模式本质分三类,对应开发中最核心的三个问题:怎么造对象、怎么拼结构、怎么做交互。以下是高频模式的Java实现和Spring场景映射。

1. 创建型模式:解决"对象怎么造"的问题

这类模式聚焦"对象创建的规则和细节",核心是控制对象的创建方式,避免重复造轮子。

(1)单例模式(Singleton)

核心 :一个类仅创建一个实例,全局共享。
Java实现(懒汉式,线程安全)

java 复制代码
public class ConfigManager {
    // 私有化实例,volatile保证可见性
    private static volatile ConfigManager instance;
    
    // 私有化构造器,禁止外部new
    private ConfigManager() {}
    
    // 双重检查锁,线程安全且性能高
    public static ConfigManager getInstance() {
        if (instance == null) {
            synchronized (ConfigManager.class) {
                if (instance == null) {
                    instance = new ConfigManager();
                }
            }
        }
        return instance;
    }
    
    // 示例方法:读取配置
    public String getConfig(String key) {
        return "配置值:" + key;
    }
}

Spring场景 :Spring容器中的Bean默认是单例(scope="singleton"),比如@Service@Controller注解的类,底层就是单例模式的实现。

(2)工厂模式(Factory)

核心 :隐藏对象创建细节,只暴露统一接口。
Java实现(简单工厂)

java 复制代码
// 产品接口
public interface Payment {
    void pay(double amount);
}

// 具体产品:微信支付
public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount + "元");
    }
}

// 具体产品:支付宝支付
public class Alipay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount + "元");
    }
}

// 工厂类:创建支付对象
public class PaymentFactory {
    public static Payment createPayment(String type) {
        if ("wechat".equals(type)) {
            return new WechatPay();
        } else if ("alipay".equals(type)) {
            return new Alipay();
        }
        throw new IllegalArgumentException("不支持的支付方式");
    }
}

// 测试
public class TestFactory {
    public static void main(String[] args) {
        // 调用方只需要指定类型,无需关心创建细节
        Payment payment = PaymentFactory.createPayment("wechat");
        payment.pay(100); // 输出:微信支付:100.0元
    }
}

Spring场景 :Spring的BeanFactoryApplicationContext就是典型的工厂模式,我们通过getBean()获取对象,无需关心Bean的创建过程。

2. 结构型模式:解决"对象怎么拼"的问题

这类模式聚焦"类/对象的组合方式",核心是让结构更灵活、更兼容。

(1)适配器模式(Adapter)

核心 :让不兼容的接口能一起工作,像"转接头"一样。
Java实现

java 复制代码
// 旧系统接口(返回XML)
public interface OldApi {
    String getXmlData();
}

// 旧系统实现
public class OldApiImpl implements OldApi {
    @Override
    public String getXmlData() {
        return "<user><name>张三</name></user>";
    }
}

// 新系统需要的接口(返回JSON)
public interface NewApi {
    String getJsonData();
}

// 适配器:把XML转成JSON
public class ApiAdapter implements NewApi {
    private OldApi oldApi;
    
    public ApiAdapter(OldApi oldApi) {
        this.oldApi = oldApi;
    }
    
    @Override
    public String getJsonData() {
        // 模拟XML转JSON的逻辑
        String xml = oldApi.getXmlData();
        return "{\"user\":{\"name\":\"张三\"}}";
    }
}

// 测试
public class TestAdapter {
    public static void main(String[] args) {
        OldApi oldApi = new OldApiImpl();
        // 适配器让旧接口适配新系统
        NewApi newApi = new ApiAdapter(oldApi);
        System.out.println(newApi.getJsonData()); // 输出JSON格式数据
    }
}

Spring场景 :SpringMVC的HandlerAdapter就是适配器模式,不同的处理器(Controller)通过适配器统一处理请求。

(2)代理模式(Proxy)

核心 :找个"中间人"控制对象访问,可加前置/后置逻辑。
Java实现(静态代理)

java 复制代码
// 业务接口
public interface OrderService {
    void createOrder(String orderNo);
}

// 真实业务实现
public class OrderServiceImpl implements OrderService {
    @Override
    public void createOrder(String orderNo) {
        System.out.println("创建订单:" + orderNo);
    }
}

// 代理类:加日志和权限校验
public class OrderServiceProxy implements OrderService {
    private OrderService target;
    
    public OrderServiceProxy(OrderService target) {
        this.target = target;
    }
    
    @Override
    public void createOrder(String orderNo) {
        // 前置逻辑:日志+权限校验
        System.out.println("日志:开始创建订单");
        if (!"admin".equals(getCurrentUser())) {
            throw new RuntimeException("无权限创建订单");
        }
        // 执行真实业务
        target.createOrder(orderNo);
        // 后置逻辑
        System.out.println("日志:订单创建完成");
    }
    
    private String getCurrentUser() {
        return "admin"; // 模拟获取当前用户
    }
}

// 测试
public class TestProxy {
    public static void main(String[] args) {
        OrderService realService = new OrderServiceImpl();
        OrderService proxyService = new OrderServiceProxy(realService);
        proxyService.createOrder("ORDER123");
    }
}

Spring场景 :Spring AOP的底层就是动态代理模式,比如@Transactional@Log注解,都是通过代理给方法加增强逻辑。

3. 行为型模式:解决"对象怎么交互"的问题

这类模式聚焦"对象之间的通信和分工",核心是让交互更灵活、解耦。

(1)策略模式(Strategy)

核心 :同一类事情有多种做法,可灵活切换,不改原代码。
Java实现

java 复制代码
// 策略接口
public interface SortStrategy {
    void sort(int[] arr);
}

// 冒泡排序策略
public class BubbleSort implements SortStrategy {
    @Override
    public void sort(int[] arr) {
        System.out.println("冒泡排序");
        // 简单实现冒泡排序
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

// 快速排序策略
public class QuickSort implements SortStrategy {
    @Override
    public void sort(int[] arr) {
        System.out.println("快速排序");
        quickSort(arr, 0, arr.length - 1);
    }
    
    private void quickSort(int[] arr, int left, int right) {
        // 快速排序实现(简化版)
        if (left >= right) return;
        int pivot = arr[right];
        int i = left - 1;
        for (int j = left; j < right; j++) {
            if (arr[j] <= pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[right];
        arr[right] = temp;
        quickSort(arr, left, i);
        quickSort(arr, i + 2, right);
    }
}

// 上下文:使用策略
public class SortContext {
    private SortStrategy strategy;
    
    // 动态切换策略
    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void sortArray(int[] arr) {
        strategy.sort(arr);
    }
}

// 测试
public class TestStrategy {
    public static void main(String[] args) {
        int[] arr = {3,1,4,1,5};
        SortContext context = new SortContext();
        
        // 使用冒泡排序
        context.setStrategy(new BubbleSort());
        context.sortArray(arr);
        
        // 切换为快速排序
        context.setStrategy(new QuickSort());
        context.sortArray(arr);
    }
}

Spring场景 :Spring的Resource接口(不同资源加载策略:文件、网络、类路径)就是策略模式的应用。

(2)观察者模式(Observer)

核心 :一个对象变化,多个对象自动收到通知。
Java实现(基于JDK自带接口)

java 复制代码
import java.util.Observable;
import java.util.Observer;

// 被观察者:商品库存
public class ProductStock extends Observable {
    private int stock;
    
    public void setStock(int stock) {
        this.stock = stock;
        // 标记状态变化
        setChanged();
        // 通知所有观察者
        notifyObservers(stock);
    }
}

// 观察者1:库存告警
public class StockAlarm implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        int stock = (int) arg;
        if (stock < 10) {
            System.out.println("告警:库存不足,当前库存:" + stock);
        }
    }
}

// 观察者2:库存日志
public class StockLog implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        int stock = (int) arg;
        System.out.println("日志:库存更新为:" + stock);
    }
}

// 测试
public class TestObserver {
    public static void main(String[] args) {
        ProductStock stock = new ProductStock();
        // 添加观察者
        stock.addObserver(new StockAlarm());
        stock.addObserver(new StockLog());
        
        // 修改库存,自动通知观察者
        stock.setStock(15); // 仅日志
        stock.setStock(8);  // 日志+告警
    }
}

Spring场景 :Spring的ApplicationEventApplicationListener就是观察者模式,比如ContextRefreshedEvent(容器刷新完成)会通知所有监听器。

二、实战:开发时如何选对设计模式?

选模式的核心是"先定问题类型,再匹配具体场景",不用死记硬背,按以下三步走:

第一步:给问题归类

问题类型 核心诉求 候选模式
创建问题 控制对象创建(数量/细节/复杂度) 单例、工厂、建造者、原型
结构问题 兼容接口/组合对象/简化调用 适配器、代理、装饰器、外观
交互问题 对象通信/灵活切换逻辑/分工处理 策略、观察者、责任链、模板方法

第二步:按场景精准匹配(高频场景)

开发场景 推荐模式 选型理由
全系统唯一实例(配置/日志/连接池) 单例模式 避免重复创建,节省资源
多类型对象创建(支付方式/数据库连接) 工厂模式 隐藏创建细节,调用方只需指定类型
新旧接口兼容(旧XML接口对接新JSON系统) 适配器模式 无需修改旧代码,适配新接口
方法增强(日志/权限/事务) 代理模式 不修改原业务,加前置/后置逻辑
多算法切换(排序/支付/限流) 策略模式 开闭原则,加新算法不用改原代码
状态变更通知(库存/订单/消息推送) 观察者模式 解耦通知方和接收方,自动同步状态

第三步:避坑(新手必看)

  1. 拒绝过度设计:简单功能(如普通POJO创建)不用模式,硬套反而增加复杂度;
  2. 优先选简单模式:小团队优先用工厂、策略、观察者等易理解的模式,避免桥接、备忘录等复杂模式;
  3. 符合开闭原则:选的模式要支持"扩展开放、修改关闭",比如加新支付方式,只需加新策略类,不用改工厂代码。

三、Spring中的设计模式总结

Spring框架本身就是设计模式的"集大成者",掌握这些对应关系,能更好理解Spring源码:

  • 单例模式:Bean默认作用域;
  • 工厂模式:BeanFactory/ApplicationContext
  • 代理模式:AOP动态代理(JDK/CGLIB);
  • 适配器模式:HandlerAdapterMessageConverter
  • 策略模式:ResourceTransactionManager
  • 观察者模式:ApplicationEvent/ApplicationListener

总结

  1. 设计模式的核心是解决特定问题的套路,而非语法规则,优先按"创建/结构/交互"三类问题匹配模式;
  2. Java/Spring开发中,工厂、单例、代理、策略、观察者是5个高频模式,覆盖80%的场景;
  3. 选模式的关键是"适配场景+避免过度设计",简单功能不用模式,复杂场景优先选团队易理解的模式。

掌握设计模式不是为了"炫技",而是让代码更易维护、更灵活------这也是设计模式的终极目标:写出"优雅且可扩展"的代码

相关推荐
技术人生黄勇2 小时前
微信接入|企业微信官方插件支持 OpenClaw 3步快速接入(实操版)
java·前端·人工智能·微信·企业微信
崔小汤2 小时前
SpringAI实战之结构化输出
java·ai
Lin_林2 小时前
国内 Docker 服务状态 & 镜像加速监控
java·开发语言
予枫的编程笔记2 小时前
【面试专栏|JVM虚拟机】从Serial到ZGC,JVM垃圾收集器进化史
java·jvm·垃圾收集器·zgc·g1 gc·serial gc·cms gc
逝水如流年轻往返染尘2 小时前
java中类和对象
java
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧2 小时前
Java 集合 (Collection)
java·开发语言
后端AI实验室2 小时前
我让AI review了自己写的代码,然后删掉了30%
java·ai
SunnyDays10112 小时前
Java 实战:将 Word 文档高效转换为多页 TIFF 图片(含批量处理)
java·word转tiff
一直都在5722 小时前
Java基础面经(二)
java·开发语言