Spring 设计模式.md
# Spring 设计模式 设计模式是软件开发过程中总结出来的常见问题解决方案,主要目的是降低代码耦合度,提高代码的可扩展性和可维护性 常见的设计原则: - 单一职责原则:一个类尽量只负责一类职责 - 开闭原则:对扩展开放,对修改关闭,即新增功能时尽量通过新增代码实现,而不是修改已有代码 - 依赖倒置原则:面向接口编程,而不是直接依赖具体实现类 注意:开闭原则并不是完全禁止修改原有代码,而是尽量减少新增功能对已有代码的影响。例如,不断增加 `if-else` 分支通常不符合开闭原则的设计目标 ## 工厂模式 核心思想:将对象的**创建与使用**分离,由工厂负责创建对象,业务代码只负责使用对象 ### 不使用工厂模式 假设有两种产品 `ProductA` 和 `ProductB`: ```java // 产品接口 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"); } } ``` 业务类直接创建产品: ```java class ProductService { public void execute(String type) { Product product; if ("A".equals(type)) { product = new ProductA(); } else if ("B".equals(type)) { product = new ProductB(); } else { throw new IllegalArgumentException("未知产品"); } product.use(); } } ``` 存在的问题: - 业务类既负责创建对象,又负责使用对象,职责混杂 - 业务类直接依赖 `ProductA`、`ProductB` 等具体实现类 - 新增产品 `ProductC` 时,需要修改 `ProductService` 中的判断逻辑 ### 使用工厂方法模式 通过工厂接口创建产品,每种产品对应一个具体工厂 产品接口及 `ProductA`、`ProductB` 保持不变,只需增加工厂相关代码: ```java // 工厂接口 interface Factory { Product createProduct(); } // 具体工厂 A class FactoryA implements Factory { public Product createProduct() { return new ProductA(); } } // 具体工厂 B class FactoryB implements Factory { public Product createProduct() { return new ProductB(); } } // 后续产品扩展 ``` 业务类不再负责创建具体产品,而是接收外部传入的工厂: ```java class ProductService { private final Factory factory; // 构造函数注入工厂 public ProductService(Factory factory) { this.factory = factory; } public void execute() { Product product = factory.createProduct(); product.use(); } } ``` 由 `Main` 决定使用哪个工厂: ```java class Main { public static void main(String[] args) { // 选择具体工厂 Factory factory = new FactoryA(); // 将工厂传递给业务类 ProductService service = new ProductService(factory); service.execute(); } } ``` 执行结果: ``` 使用产品 A ``` 如果需要使用产品 B,只需修改 `Main` 中的工厂选择: ```java Factory factory = new FactoryB(); ``` 此时,`ProductService` 不需要任何修改,因为它只依赖 `Factory` 接口,不关心具体工厂与产品 如果后续新增产品 C,只需新增 `ProductC` 和 `FactoryC`,原有业务类不需要修改,注意: 1. 工厂方法模式并不是让整个程序完全不需要修改代码,而是将变化集中在工厂选择与对象创建部分,减少对业务逻辑的影响 2. `Main` 仍需要选择具体工厂,实际开发中可以结合配置或 Spring 依赖注入完成 3. 如果对象创建非常简单,也可以直接通过构造函数注入 `Product` 接口实现解耦,不一定需要额外引入工厂模式 ### Spring 中的应用 Spring IoC 容器也体现了类似思想:将 Bean 的创建和依赖管理交给容器,而不是由业务类自行创建依赖对象 ```java @Service class ProductService { public void use() { System.out.println("使用产品"); } } @RestController class ProductController { private final ProductService productService; // 通过构造函数注入 public ProductController(ProductService productService) { this.productService = productService; } } ``` 这里: - `ProductController` 不需要自行 `new ProductService()` - Spring 容器负责创建 `ProductService` Bean,并注入到 `ProductController` - 对象创建与依赖管理交由 Spring 容器完成 Spring 中与工厂模式相关的典型接口: - `BeanFactory`:Spring IoC 容器的基础接口,提供获取和管理 Bean 的能力 - `FactoryBean`:特殊的工厂 Bean,用于封装特定对象的创建逻辑 需要区分: - 工厂模式:解决对象由谁创建、如何创建的问题 - 依赖注入(DI):解决对象的依赖由谁提供的问题 - Spring IoC:由容器统一负责对象创建、依赖注入及生命周期管理等工作 ### 面试速记 工厂模式将对象的**创建与使用分离**,创建由工厂负责,使用则由业务代码处理 ## 单例模式 > [05 单例模式(创建型)_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1oYQLBiESn/?spm_id_from=333.788.videopod.sections&vd_source=8c5774f0412cfb872126f5a44585db4f&p=8) 在 Java 中,一个类可以有多个实例,通过 new 便能创建新的实例,但在实际开发中,部分对象不需要反复创建,如:配置管理器、日志记录器等 单例模式保证了一个类只有一个实例,并提供全局访问点 > 注意:数据库连接池管理器可以设计为单例,但数据库连接池中的连接不是单例,一个连接池通常管理多个数据库连接 ### 单例模式的实现方式 常见的实现方式有两种:饿汉式和懒汉式,主要区别在于对象创建的时机 #### 饿汉式 类初始化时便创建实例,无论后续是否使用 ```java public class Singleton { // 类初始化时创建实例 private static final Singleton INSTANCE = new Singleton(); // 私有构造函数,防止外部 new private Singleton() {} // 提供全局访问点 public static Singleton getInstance() { return INSTANCE; } } ``` 特点: - 实现简单,线程安全(由 JVM 类初始化机制保证) - 即使没有使用该实例,也会在类初始化时创建 #### 懒汉式 第一次获取实例时才创建对象,实现延迟加载 ```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; } } ``` 这里采用双重检查锁(DCL): - 第一次判断:实例存在时直接返回,避免每次获取都加锁 - `synchronized`:保证多个线程不会同时创建实例 - 第二次判断:避免多个线程依次获得锁后重复创建 - `volatile`:保证可见性,并禁止影响安全发布的指令重排序 ### Spring 中的单例模式 Spring 中的 Bean 默认采用 `singleton` (单例)作用域 核心思想:通过 map 缓存管理 Bean,存在则直接返回,不存在则创建 ```java // 通过 ConcurrentHashMap(线程安全) 实现单例注册表 private final Map singletonObjects = new ConcurrentHashMap(64); public Object getSingleton(String beanName, ObjectFactory singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { // 检查缓存中是否存在实例 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //...省略了很多代码 try { singletonObject = singletonFactory.getObject(); } //...省略了很多代码 // 如果实例对象在不存在,我们注册到单例注册表中。 addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } } //将对象添加到单例注册表 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ?
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与