当前位置: 首页 > news >正文

设计模式详解:单例模式、工厂方法模式、抽象工厂模式

设计模式详解:单例模式、工厂方法模式、抽象工厂模式

目录

  1. 单例模式
  2. 工厂方法模式
  3. 抽象工厂模式
  4. 三种模式对比总结
  5. 面试高频点总结

单例模式

简介

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。单例模式的核心思想是控制实例的创建过程,保证系统中只有一个实例存在。

核心流程

  1. 私有化构造函数:防止外部直接创建实例
  2. 提供静态方法:作为全局访问点
  3. 延迟初始化:在需要时才创建实例
  4. 线程安全:确保多线程环境下的安全性
单例模式流程图
存在
不存在
客户端请求实例
实例是否已存在?
返回现有实例
是否线程安全?
创建新实例
加锁
再次检查实例
返回现有实例
创建新实例
释放锁
返回新实例
使用实例

实现方式

单例模式实现方式对比流程图
单例模式实现方式
饿汉式
懒汉式
双重检查锁定
静态内部类
枚举
类加载时创建实例
线程安全
可能浪费内存
延迟创建实例
非线程安全
需要加锁优化
延迟创建实例
双重检查保证线程安全
volatile防止重排序
延迟创建实例
JVM保证线程安全
推荐使用
类加载时创建实例
JVM保证线程安全
防止反射攻击
1. 饿汉式(线程安全)
public class EagerSingleton {private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}
}
2. 懒汉式(非线程安全)
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
3. 双重检查锁定(线程安全)
public class DoubleCheckSingleton {private static volatile DoubleCheckSingleton instance;private DoubleCheckSingleton() {}public static DoubleCheckSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckSingleton.class) {if (instance == null) {instance = new DoubleCheckSingleton();}}}return instance;}
}
4. 枚举单例(推荐)
public enum EnumSingleton {INSTANCE;public void doSomething() {// 业务逻辑}
}

重难点分析

重难点1:线程安全问题
  • 问题:多线程环境下可能创建多个实例
  • 解决方案
    • 使用synchronized关键字
    • 使用volatile关键字防止指令重排序
    • 使用枚举实现(JVM保证线程安全)
重难点2:序列化问题
  • 问题:反序列化时可能创建新实例
  • 解决方案:实现readResolve()方法
private Object readResolve() {return instance;
}
重难点3:反射攻击
  • 问题:通过反射可以绕过私有构造函数
  • 解决方案:在构造函数中检查实例是否已存在
private LazySingleton() {if (instance != null) {throw new RuntimeException("单例模式被破坏");}
}

Spring中的源码分析

ApplicationContext的单例实现
// AbstractApplicationContext.java
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {// 单例Bean的缓存private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);@Overridepublic Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);}protected <T> T doGetBean(String name, @Nullable Class<T> requiredType,@Nullable Object[] args, boolean typeCheckOnly) throws BeansException {// 先从单例缓存中获取Object sharedInstance = getSingleton(name);if (sharedInstance != null && args == null) {bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}// ... 其他逻辑}
}
DefaultSingletonBeanRegistry
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {// 单例Bean的缓存private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 单例工厂的缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
}

具体使用场景

  1. 配置管理器:全局配置信息
  2. 数据库连接池:避免重复创建连接
  3. 日志记录器:统一日志输出
  4. 缓存管理器:全局缓存控制
  5. 线程池:资源池管理

工厂方法模式

简介

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。

核心流程

  1. 定义抽象产品接口:声明产品的通用方法
  2. 定义具体产品类:实现产品接口
  3. 定义抽象工厂接口:声明创建产品的方法
  4. 定义具体工厂类:实现创建具体产品的逻辑
  5. 客户端调用:通过工厂创建产品
工厂方法模式流程图
产品层次
工厂层次
具体产品A
抽象产品接口
具体产品B
具体工厂A
抽象工厂接口
具体工厂B
创建产品A
创建产品B
客户端
选择具体工厂
调用工厂方法
工厂创建产品
返回具体产品
客户端使用产品

实现示例

产品接口和实现
// 抽象产品
public interface Product {void use();
}// 具体产品A
public class ConcreteProductA implements Product {@Overridepublic void use() {System.out.println("使用产品A");}
}// 具体产品B
public class ConcreteProductB implements Product {@Overridepublic void use() {System.out.println("使用产品B");}
}
工厂接口和实现
// 抽象工厂
public interface ProductFactory {Product createProduct();
}// 具体工厂A
public class ConcreteProductAFactory implements ProductFactory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具体工厂B
public class ConcreteProductBFactory implements ProductFactory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}
客户端使用
public class Client {public static void main(String[] args) {ProductFactory factoryA = new ConcreteProductAFactory();Product productA = factoryA.createProduct();productA.use();ProductFactory factoryB = new ConcreteProductBFactory();Product productB = factoryB.createProduct();productB.use();}
}

重难点分析

工厂方法模式演进流程图
抽象工厂模式
工厂方法模式
简单工厂模式
具体工厂类
抽象工厂接口
每个工厂创建产品族
支持产品族扩展
具体工厂类
抽象工厂接口
每个工厂创建一种产品
符合开闭原则
创建所有产品
一个工厂类
违反开闭原则
简单工厂模式
工厂方法模式
抽象工厂模式
重难点1:开闭原则
  • 问题:如何在不修改现有代码的情况下添加新产品
  • 解决方案:通过添加新的具体工厂类来支持新产品
重难点2:依赖倒置
  • 问题:高层模块不应该依赖低层模块
  • 解决方案:依赖抽象而不是具体实现
重难点3:工厂选择策略
  • 问题:如何选择合适的工厂
  • 解决方案
    • 配置文件驱动
    • 策略模式结合
    • 简单工厂模式结合

Spring中的源码分析

BeanFactory接口
public interface BeanFactory {Object getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;// ... 其他方法
}
DefaultListableBeanFactory
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {@Overridepublic <T> T getBean(Class<T> requiredType) throws BeansException {return getBean(requiredType, (Object[]) null);}@Overridepublic <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {Assert.notNull(requiredType, "Required type must not be null");String[] beanNames = getBeanNamesForType(requiredType);if (beanNames.length > 1) {// 处理多个候选Bean的情况return resolveNamedBean(requiredType, beanNames, args);} else if (beanNames.length == 1) {return getBean(beanNames[0], requiredType, args);} else {throw new NoSuchBeanDefinitionException(requiredType, "expected at least 1 bean which qualifies as autowire candidate");}}
}
FactoryBean接口
public interface FactoryBean<T> {T getObject() throws Exception;Class<?> getObjectType();boolean isSingleton();
}

具体使用场景

  1. 数据库连接工厂:不同类型的数据库连接
  2. 日志记录器工厂:不同级别的日志记录器
  3. 加密算法工厂:不同加密算法的实现
  4. UI组件工厂:不同平台的UI组件
  5. 数据解析器工厂:不同格式的数据解析器

抽象工厂模式

简介

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式是工厂方法模式的扩展。

核心流程

  1. 定义抽象产品族:声明多个相关的产品接口
  2. 定义具体产品族:实现每个产品接口
  3. 定义抽象工厂:声明创建产品族的方法
  4. 定义具体工厂:实现创建具体产品族的逻辑
  5. 客户端调用:通过工厂创建产品族
抽象工厂模式流程图
产品族关系
产品族层次
抽象工厂层次
产品族1: A1 + B1
产品族2: A2 + B2
具体产品A1
抽象产品A
具体产品A2
具体产品B1
抽象产品B
具体产品B2
具体工厂1
抽象工厂接口
具体工厂2
创建产品族1
创建产品族2
客户端
选择具体工厂
调用抽象工厂方法
工厂创建产品族
返回产品族对象
客户端使用产品族

实现示例

产品族接口
// 抽象产品A
public interface ProductA {void operationA();
}// 抽象产品B
public interface ProductB {void operationB();
}// 具体产品A1
public class ConcreteProductA1 implements ProductA {@Overridepublic void operationA() {System.out.println("产品A1的操作");}
}// 具体产品A2
public class ConcreteProductA2 implements ProductA {@Overridepublic void operationA() {System.out.println("产品A2的操作");}
}// 具体产品B1
public class ConcreteProductB1 implements ProductB {@Overridepublic void operationB() {System.out.println("产品B1的操作");}
}// 具体产品B2
public class ConcreteProductB2 implements ProductB {@Overridepublic void operationB() {System.out.println("产品B2的操作");}
}
抽象工厂和具体工厂
// 抽象工厂
public interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {return new ConcreteProductB2();}
}
客户端使用
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();AbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}

重难点分析

重难点1:产品族的扩展
  • 问题:如何添加新的产品族
  • 解决方案:创建新的具体工厂类
重难点2:产品族的约束
  • 问题:如何保证产品族内产品的一致性
  • 解决方案:在抽象工厂中定义产品族的创建规则
重难点3:工厂选择策略
  • 问题:如何选择合适的工厂
  • 解决方案
    • 配置文件驱动
    • 环境变量控制
    • 策略模式结合

Spring中的源码分析

ApplicationContext作为抽象工厂
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {// 获取不同类型的BeanObject getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;// 获取Bean的提供者<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
}
ConfigurableApplicationContext
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {// 配置Bean定义void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);// 刷新上下文void refresh() throws BeansException, IllegalStateException;// 注册关闭钩子void registerShutdownHook();
}
AbstractApplicationContext的实现
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 准备刷新prepareRefresh();// 获取BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 准备BeanFactoryprepareBeanFactory(beanFactory);try {// 后处理BeanFactorypostProcessBeanFactory(beanFactory);// 调用BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// 注册BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 初始化MessageSourceinitMessageSource();// 初始化ApplicationEventMulticasterinitApplicationEventMulticaster();// 刷新特定上下文onRefresh();// 注册监听器registerListeners();// 实例化所有非懒加载的单例BeanfinishBeanFactoryInitialization(beanFactory);// 完成刷新finishRefresh();} catch (BeansException ex) {// 异常处理destroyBeans();cancelRefresh(ex);throw ex;} finally {resetCommonCaches();}}}
}

具体使用场景

  1. UI框架:不同操作系统的UI组件
  2. 数据库访问层:不同数据库的DAO实现
  3. 游戏引擎:不同平台的游戏资源
  4. 消息队列:不同消息中间件的实现
  5. 缓存系统:不同缓存技术的实现

三种模式对比总结

三种模式对比流程图

模式特点对比
抽象工厂模式
工厂方法模式
单例模式
单例: 1个实例
工厂方法: 1个产品
抽象工厂: 1个产品族
选择具体工厂
客户端
调用createProductA/B
工厂创建产品族
返回产品族对象
选择具体工厂
客户端
调用createProduct
工厂创建产品
返回具体产品
调用getInstance
客户端
实例存在?
返回现有实例
创建新实例
返回新实例

模式对比表格

特性单例模式工厂方法模式抽象工厂模式
目的确保只有一个实例创建单一产品创建产品族
复杂度简单中等复杂
扩展性难以扩展易于扩展新产品难以扩展新产品族
使用场景配置管理、连接池单一产品创建相关产品族创建
Spring应用Bean单例管理FactoryBeanApplicationContext
设计原则单一职责开闭原则开闭原则

选择指南

何时使用单例模式?
  • 需要全局唯一的实例
  • 资源消耗大的对象(如数据库连接池)
  • 配置管理器
  • 日志记录器
何时使用工厂方法模式?
  • 需要创建单一类型的产品
  • 产品类型可能变化
  • 需要解耦产品创建和使用
  • 符合开闭原则要求
何时使用抽象工厂模式?
  • 需要创建相关的产品族
  • 产品族内产品需要保持一致
  • 系统需要支持多个产品族
  • 产品族相对稳定

实际项目中的应用建议

  1. 简单配置管理 → 单例模式
  2. 数据访问层 → 工厂方法模式
  3. UI框架 → 抽象工厂模式
  4. 缓存系统 → 单例模式 + 工厂方法模式
  5. 插件系统 → 抽象工厂模式

面试高频点总结

面试知识点思维导图

设计模式面试点
单例模式
工厂方法模式
抽象工厂模式
设计原则
实际应用
实现方式
线程安全
序列化问题
反射攻击
Spring实现
饿汉式
懒汉式
双重检查锁定
静态内部类
枚举
synchronized
volatile
指令重排序
readResolve
构造函数检查
BeanFactory
ConcurrentHashMap
与简单工厂区别
解决的问题
Spring实现
开闭原则
扩展性
解耦
可维护性
FactoryBean
getObject方法
与工厂方法区别
优缺点
模式选择
产品族
复杂度
产品一致性
扩展困难
简单创建
单一产品
产品族
单一职责
开闭原则
里氏替换
接口隔离
依赖倒置
Spring框架
MyBatis
数据库连接池
日志框架

单例模式面试点

1. 单例模式的实现方式有哪些?
  • 饿汉式(线程安全,但可能浪费内存)
  • 懒汉式(非线程安全)
  • 双重检查锁定(线程安全,性能较好)
  • 静态内部类(线程安全,延迟加载)
  • 枚举(线程安全,防止反射攻击)
2. 为什么双重检查锁定需要volatile关键字?
  • 防止指令重排序
  • 确保多线程环境下的可见性
  • 避免创建不完整的对象
3. 单例模式在Spring中是如何实现的?
  • 通过BeanFactory管理单例Bean
  • 使用ConcurrentHashMap缓存单例对象
  • 支持单例、原型、请求、会话等作用域

工厂方法模式面试点

1. 工厂方法模式与简单工厂模式的区别?
  • 简单工厂:一个工厂类创建所有产品
  • 工厂方法:每个产品对应一个工厂类
  • 工厂方法模式更符合开闭原则
2. 工厂方法模式解决了什么问题?
  • 解耦产品创建和使用
  • 支持开闭原则
  • 提高代码的可维护性
3. Spring中的FactoryBean是什么?
  • 特殊的Bean,用于创建其他Bean
  • 实现FactoryBean接口
  • 通过getObject()方法返回实际对象

抽象工厂模式面试点

1. 抽象工厂模式与工厂方法模式的区别?
  • 工厂方法:一个工厂创建一个产品
  • 抽象工厂:一个工厂创建一系列相关产品
  • 抽象工厂模式更复杂,但更灵活
2. 抽象工厂模式的优缺点?
  • 优点:支持产品族,保证产品一致性
  • 缺点:难以扩展新产品,增加系统复杂度
3. 如何选择合适的设计模式?
  • 简单创建:简单工厂
  • 单一产品:工厂方法
  • 产品族:抽象工厂
  • 复杂创建:建造者模式

综合面试点

1. 设计模式的原则?
  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 接口隔离原则
  • 依赖倒置原则
2. 创建型模式的特点?
  • 关注对象的创建过程
  • 隐藏创建细节
  • 提供灵活的创建方式
  • 支持开闭原则
3. 在项目中的实际应用?
  • Spring框架中的Bean管理
  • MyBatis中的SqlSessionFactory
  • 数据库连接池的实现
  • 日志框架的设计

总结

本文详细介绍了三种重要的创建型设计模式:

  1. 单例模式:确保类只有一个实例,适用于配置管理、连接池等场景
  2. 工厂方法模式:将产品创建延迟到子类,适用于需要扩展产品的场景
  3. 抽象工厂模式:创建产品族,适用于需要保证产品一致性的场景

每种模式都有其特定的使用场景和实现方式,在实际开发中需要根据具体需求选择合适的设计模式。Spring框架中大量使用了这些设计模式,理解这些模式有助于更好地使用和理解Spring框架。

在面试中,除了要掌握这些模式的基本概念和实现方式外,还要能够结合实际项目经验,说明在什么情况下使用哪种模式,以及如何解决实际开发中遇到的问题。

http://www.dtcms.com/a/390973.html

相关文章:

  • 终端同居物语:Shell咏唱术式与权限结界の完全解析书
  • XeLaTeX 中文删除线自动换行问题的解决方案
  • R语言中的因子(Factor)详解 factor_path <- as.factor(char_path)
  • 软件测试之⾃动化测试常⽤函数(沉淀中)
  • 火山引擎多模态数据湖:基于 Daft 与 Lance,构筑 AI 时代数据湖新范式
  • 关于强化学习的一篇经典学习文章
  • 【JavaScript 性能优化实战】第四篇:webpack 与 vite 打包优化实战
  • maven-profile实现springboot多版本配置打包
  • OpenLayers地图交互 -- 章节二:绘制交互详解:从基础几何到复杂图形的完整绘制方案
  • Java 工厂模式 + 策略模式实战:工具管理器的设计与实现
  • 污水处理厂远程调试与智能化运维解决方案
  • 【提示工程】Ch2-提示技术(Prompt Technique)
  • vLLM - Worker
  • GitHub上面仓库名写错了,怎么改
  • 项目中的图形验证码是前端还是后端实现?
  • ✅ 基于Scrapy与朴素贝叶斯的校园舆情监测与预警系统 Django+B/S架构 可视化大屏 机器学习
  • Unity UI 插件 | Easy Popup System
  • AI证件照制作 API 快速生成证件照
  • @RequestParam和 @RequestBody能一起用吗
  • 构建高效的电商爬虫代理池:从架构设计到实战优化
  • 使用cJSON库实现JSON与C结构体的互转
  • Cursor :Python 运行路径设置自定义模块导入报错:No module named ‘xxx’ 的解决方案
  • 数图信息科技亮相唐山社区零售论坛,数字化赋能行业高质量发展
  • LLM大模型 - 实战篇 - Assistant API 原理与实战应用
  • python微博舆情分析系统 情感分析 爬虫 机器学习 新浪微博 数据采集 大数据技术(源码)✅
  • FreeRTOS消息队列剖析讲解(思路+源码)
  • Trillium Engineering-无人机万向节有效负载 - 用于战术 UAS 的 EO 和 EO/IR 无人机相机万向节
  • 【Linux网络】Socket编程预备
  • pyAutoGUI 模块主要功能介绍-(4)消息框功能
  • 自学嵌入式第四十三天:硬件方面-ARM体系架构