Java设计模式(一):单例模式与工厂模式

简介: 本文详解单例模式与工厂模式的核心实现及应用,涵盖饿汉式、懒汉式、双重检查锁、工厂方法、抽象工厂等设计模式,并结合数据库连接池与支付系统实战案例,助你掌握设计模式精髓,提升代码专业性与可维护性。

💡 摘要:你是否曾需要确保一个类只有一个实例?是否厌倦了到处使用new关键字创建对象?是否想写出更灵活、更易维护的代码?

别担心,设计模式是软件设计中经过验证的最佳实践解决方案。单例模式和工厂模式作为最常用的两种创建型模式,能帮你解决对象创建和管理的各种问题。

本文将带你从单例模式的各种实现讲起,理解如何保证一个类只有一个实例。然后深入工厂模式的多种变体,学习如何优雅地创建对象。最后通过实战案例展示这两种模式在框架开发、业务逻辑中的实际应用。从线程安全到性能优化,从简单实现到高级技巧,让你全面掌握这两种核心设计模式。文末附常见陷阱和面试高频问题,助你写出更专业的代码。

一、单例模式:确保唯一实例

1. 单例模式的核心概念

单例模式定义:保证一个类只有一个实例,并提供一个全局访问点。

适用场景

  • ✅ 需要频繁创建和销毁的对象
  • ✅ 创建对象耗时过多或耗资源过多
  • ✅ 工具类对象
  • ✅ 频繁访问数据库或文件的对象

2. 饿汉式单例(Eager Initialization)

最简单的实现

java

public class EagerSingleton {

   // 类加载时就创建实例

   private static final EagerSingleton INSTANCE = new EagerSingleton();

   

   // 私有构造器,防止外部创建实例

   private EagerSingleton() {

       // 防止通过反射创建实例

       if (INSTANCE != null) {

           throw new RuntimeException("单例模式禁止反射创建");

       }

   }

   

   // 全局访问点

   public static EagerSingleton getInstance() {

       return INSTANCE;

   }

   

   // 业务方法

   public void doSomething() {

       System.out.println("饿汉式单例执行操作");

   }

}

优点:实现简单,线程安全

缺点:类加载时就创建实例,可能造成资源浪费

3. 懒汉式单例(Lazy Initialization)

基础懒汉式(线程不安全)

java

public class LazySingleton {

   private static LazySingleton instance;

   

   private LazySingleton() {}

   

   // 线程不安全版本

   public static LazySingleton getInstance() {

       if (instance == null) {

           instance = new LazySingleton();

       }

       return instance;

   }

}

同步懒汉式(线程安全但性能差)

java

public class SynchronizedSingleton {

   private static SynchronizedSingleton instance;

   

   private SynchronizedSingleton() {}

   

   // 同步方法,线程安全但性能差

   public static synchronized SynchronizedSingleton getInstance() {

       if (instance == null) {

           instance = new SynchronizedSingleton();

       }

       return instance;

   }

}

4. 双重检查锁(Double-Checked Locking)

最优的懒汉式实现

java

public class DoubleCheckedSingleton {

   // 使用volatile防止指令重排序

   private static volatile DoubleCheckedSingleton instance;

   

   private DoubleCheckedSingleton() {

       // 防止反射攻击

       if (instance != null) {

           throw new RuntimeException("禁止反射创建单例");

       }

   }

   

   public static DoubleCheckedSingleton getInstance() {

       // 第一次检查,避免不必要的同步

       if (instance == null) {

           synchronized (DoubleCheckedSingleton.class) {

               // 第二次检查,确保只有一个线程创建实例

               if (instance == null) {

                   instance = new DoubleCheckedSingleton();

               }

           }

       }

       return instance;

   }

}

volatile的重要性

java

// 没有volatile时可能发生的问题:

// instance = new Singleton() 分为三步:

// 1. 分配内存空间

// 2. 初始化对象

// 3. 将instance指向内存空间


// 可能发生指令重排序:1→3→2

// 其他线程可能在对象未完全初始化时看到instance不为null

5. 静态内部类实现(推荐方式)

线程安全且懒加载

java

public class InnerClassSingleton {

   

   private InnerClassSingleton() {

       // 防止反射攻击

       if (SingletonHolder.INSTANCE != null) {

           throw new RuntimeException("禁止反射创建单例");

       }

   }

   

   // 静态内部类在第一次使用时加载

   private static class SingletonHolder {

       private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();

   }

   

   public static InnerClassSingleton getInstance() {

       return SingletonHolder.INSTANCE;

   }

   

   // 防止反序列化破坏单例

   protected Object readResolve() {

       return getInstance();

   }

}

优点:线程安全、懒加载、实现简单

6. 枚举单例(最佳实践)

Joshua Bloch推荐的方式

java

public enum EnumSingleton {

   INSTANCE;

   

   // 添加业务方法

   private int counter = 0;

   

   public void doSomething() {

       System.out.println("枚举单例执行操作,计数器: " + (++counter));

   }

   

   public int getCounter() {

       return counter;

   }

}


// 使用示例

public class EnumSingletonClient {

   public static void main(String[] args) {

       EnumSingleton.INSTANCE.doSomething(); // 计数器: 1

       EnumSingleton.INSTANCE.doSomething(); // 计数器: 2

       

       // 线程安全测试

       for (int i = 0; i < 10; i++) {

           new Thread(() -> {

               EnumSingleton.INSTANCE.doSomething();

           }).start();

       }

   }

}

枚举单例的优势

  • ✅ 绝对防止多次实例化
  • ✅ 自动处理序列化问题
  • ✅ 线程安全
  • ✅ 防止反射攻击

二、工厂模式:优雅的对象创建

1. 简单工厂模式(Simple Factory)

基础实现

java

// 产品接口

public interface Product {

   void use();

}


// 具体产品

public class ConcreteProductA implements Product {

   @Override

   public void use() {

       System.out.println("使用产品A");

   }

}


public class ConcreteProductB implements Product {

   @Override

   public void use() {

       System.out.println("使用产品B");

   }

}


// 简单工厂

public class SimpleFactory {

   public static Product createProduct(String type) {

       switch (type) {

           case "A":

               return new ConcreteProductA();

           case "B":

               return new ConcreteProductB();

           default:

               throw new IllegalArgumentException("未知产品类型: " + type);

       }

   }

}


// 使用示例

public class SimpleFactoryClient {

   public static void main(String[] args) {

       Product productA = SimpleFactory.createProduct("A");

       productA.use(); // 使用产品A

       

       Product productB = SimpleFactory.createProduct("B");

       productB.use(); // 使用产品B

   }

}

2. 工厂方法模式(Factory Method)

定义创建接口

java

// 抽象创建者

public abstract class Creator {

   // 工厂方法

   public abstract Product createProduct();

   

   // 业务方法

   public void doSomething() {

       Product product = createProduct();

       product.use();

   }

}


// 具体创建者

public class ConcreteCreatorA extends Creator {

   @Override

   public Product createProduct() {

       return new ConcreteProductA();

   }

}


public class ConcreteCreatorB extends Creator {

   @Override

   public Product createProduct() {

       return new ConcreteProductB();

   }

}


// 使用示例

public class FactoryMethodClient {

   public static void main(String[] args) {

       Creator creatorA = new ConcreteCreatorA();

       creatorA.doSomething(); // 使用产品A

       

       Creator creatorB = new ConcreteCreatorB();

       creatorB.doSomething(); // 使用产品B

   }

}

3. 抽象工厂模式(Abstract Factory)

产品族创建

java

// 抽象产品族

public interface Button {

   void render();

}


public interface TextField {

   void input();

}


// 具体产品 - Windows风格

public class WindowsButton implements Button {

   @Override

   public void render() {

       System.out.println("渲染Windows风格按钮");

   }

}


public class WindowsTextField implements TextField {

   @Override

   public void input() {

       System.out.println("Windows文本框输入");

   }

}


// 具体产品 - Mac风格

public class MacButton implements Button {

   @Override

   public void render() {

       System.out.println("渲染Mac风格按钮");

   }

}


public class MacTextField implements TextField {

   @Override

   public void input() {

       System.out.println("Mac文本框输入");

   }

}


// 抽象工厂

public interface GUIFactory {

   Button createButton();

   TextField createTextField();

}


// 具体工厂

public class WindowsFactory implements GUIFactory {

   @Override

   public Button createButton() {

       return new WindowsButton();

   }

   

   @Override

   public TextField createTextField() {

       return new WindowsTextField();

   }

}


public class MacFactory implements GUIFactory {

   @Override

   public Button createButton() {

       return new MacButton();

   }

   

   @Override

   public TextField createTextField() {

       return new MacTextField();

   }

}


// 使用示例

public class AbstractFactoryClient {

   private Button button;

   private TextField textField;

   

   public AbstractFactoryClient(GUIFactory factory) {

       button = factory.createButton();

       textField = factory.createTextField();

   }

   

   public void renderUI() {

       button.render();

       textField.input();

   }

   

   public static void main(String[] args) {

       // 创建Windows风格UI

       GUIFactory windowsFactory = new WindowsFactory();

       AbstractFactoryClient windowsClient = new AbstractFactoryClient(windowsFactory);

       windowsClient.renderUI();

       

       // 创建Mac风格UI

       GUIFactory macFactory = new MacFactory();

       AbstractFactoryClient macClient = new AbstractFactoryClient(macFactory);

       macClient.renderUI();

   }

}

三、实战应用案例

1. 数据库连接池(单例模式)

连接池单例实现

java

public class ConnectionPool {

   private static final int MAX_POOL_SIZE = 10;

   private static ConnectionPool instance;

   

   private final List<Connection> connections;

   private final String url;

   private final String user;

   private final String password;

   

   private ConnectionPool(String url, String user, String password) {

       this.url = url;

       this.user = user;

       this.password = password;

       this.connections = new ArrayList<>(MAX_POOL_SIZE);

       initializePool();

   }

   

   // 双重检查锁实现

   public static ConnectionPool getInstance(String url, String user, String password) {

       if (instance == null) {

           synchronized (ConnectionPool.class) {

               if (instance == null) {

                   instance = new ConnectionPool(url, user, password);

               }

           }

       }

       return instance;

   }

   

   private void initializePool() {

       try {

           for (int i = 0; i < MAX_POOL_SIZE; i++) {

               Connection conn = DriverManager.getConnection(url, user, password);

               connections.add(conn);

           }

       } catch (SQLException e) {

           throw new RuntimeException("初始化连接池失败", e);

       }

   }

   

   public synchronized Connection getConnection() {

       while (connections.isEmpty()) {

           try {

               wait(); // 等待连接释放

           } catch (InterruptedException e) {

               Thread.currentThread().interrupt();

               throw new RuntimeException("等待连接中断", e);

           }

       }

       return connections.remove(connections.size() - 1);

   }

   

   public synchronized void releaseConnection(Connection conn) {

       connections.add(conn);

       notifyAll(); // 通知等待的线程

   }

}

2. 支付系统(工厂模式)

支付方式工厂

java

// 支付接口

public interface Payment {

   boolean pay(double amount);

   String getType();

}


// 具体支付方式

public class AlipayPayment implements Payment {

   @Override

   public boolean pay(double amount) {

       System.out.println("支付宝支付: " + amount + "元");

       // 调用支付宝API

       return true;

   }

   

   @Override

   public String getType() {

       return "alipay";

   }

}


public class WechatPayment implements Payment {

   @Override

   public boolean pay(double amount) {

       System.out.println("微信支付: " + amount + "元");

       // 调用微信API

       return true;

   }

   

   @Override

   public String getType() {

       return "wechat";

   }

}


public class BankCardPayment implements Payment {

   @Override

   public boolean pay(double amount) {

       System.out.println("银行卡支付: " + amount + "元");

       // 调用银行API

       return true;

   }

   

   @Override

   public String getType() {

       return "bankcard";

   }

}


// 支付工厂

public class PaymentFactory {

   public static Payment createPayment(String type) {

       switch (type.toLowerCase()) {

           case "alipay":

               return new AlipayPayment();

           case "wechat":

               return new WechatPayment();

           case "bankcard":

               return new BankCardPayment();

           default:

               throw new IllegalArgumentException("不支持的支付方式: " + type);

       }

   }

   

   // 通过配置文件创建

   public static Payment createPaymentFromConfig() {

       Properties props = loadPaymentConfig();

       String defaultPayment = props.getProperty("default.payment");

       return createPayment(defaultPayment);

   }

   

   private static Properties loadPaymentConfig() {

       Properties props = new Properties();

       try (InputStream input = PaymentFactory.class.getResourceAsStream("/payment.properties")) {

           props.load(input);

       } catch (IOException e) {

           throw new RuntimeException("加载支付配置失败", e);

       }

       return props;

   }

}


// 使用示例

public class PaymentSystem {

   public static void main(String[] args) {

       // 根据用户选择创建支付方式

       Payment payment = PaymentFactory.createPayment("alipay");

       payment.pay(100.0);

       

       // 根据配置创建默认支付方式

       Payment defaultPayment = PaymentFactory.createPaymentFromConfig();

       defaultPayment.pay(200.0);

   }

}

四、模式对比与选择指南

1. 单例模式变体对比

实现方式 线程安全 懒加载 防止反射 防止序列化 性能
饿汉式 ⭐⭐⭐⭐⭐
同步懒汉式 ⭐⭐
双重检查锁 ⭐⭐⭐⭐
静态内部类 ⭐⭐⭐⭐⭐
枚举 ⭐⭐⭐⭐⭐

2. 工厂模式变体对比

模式 适用场景 优点 缺点
简单工厂 产品类型较少,变化不频繁 简单易用 违反开闭原则
工厂方法 产品类型较多,需要扩展 符合开闭原则 类数量增多
抽象工厂 产品族创建,需要保证兼容性 保证产品兼容性 扩展产品族困难

五、常见陷阱与最佳实践

1. 单例模式陷阱

反射攻击防护

java

public class SafeSingleton {

   private static volatile SafeSingleton instance;

   

   private SafeSingleton() {

       // 防止反射攻击

       if (instance != null) {

           throw new RuntimeException("禁止通过反射创建单例");

       }

   }

   

   public static SafeSingleton getInstance() {

       // 双重检查锁

       if (instance == null) {

           synchronized (SafeSingleton.class) {

               if (instance == null) {

                   instance = new SafeSingleton();

               }

           }

       }

       return instance;

   }

   

   // 防止反序列化创建新实例

   protected Object readResolve() {

       return getInstance();

   }

}

2. 工厂模式最佳实践

使用依赖注入

java

// 使用Spring框架的依赖注入

@Component

public class PaymentService {

   private final Map<String, Payment> paymentStrategies;

   

   // 通过构造函数注入所有支付策略

   public PaymentService(List<Payment> payments) {

       paymentStrategies = payments.stream()

           .collect(Collectors.toMap(Payment::getType, Function.identity()));

   }

   

   public boolean processPayment(String type, double amount) {

       Payment payment = paymentStrategies.get(type);

       if (payment == null) {

           throw new IllegalArgumentException("不支持的支付方式: " + type);

       }

       return payment.pay(amount);

   }

}

六、总结:模式选择指南

1. 单例模式使用场景

  • ✅ 配置信息管理
  • ✅ 数据库连接池
  • ✅ 日志记录器
  • ✅ 应用计数器
  • ✅ 线程池管理

2. 工厂模式使用场景

  • ✅ 对象创建逻辑复杂
  • ✅ 需要统一创建接口
  • ✅ 需要动态选择实现类
  • ✅ 系统需要支持多种产品族

七、面试高频问题

❓1. 单例模式有哪些实现方式?哪种最好?

:饿汉式、懒汉式、双重检查锁、静态内部类、枚举。枚举方式最好,因为它线程安全、防止反射和序列化攻击、实现简单。

❓2. 双重检查锁为什么要用volatile?

:防止指令重排序,避免其他线程看到未完全初始化的实例。

❓3. 工厂方法模式和抽象工厂模式有什么区别?

:工厂方法模式针对一个产品等级结构,抽象工厂模式针对多个产品等级结构(产品族)。

❓4. 如何防止单例模式被反射破坏?

:在私有构造器中检查实例是否已存在,如果已存在则抛出异常。

❓5. 什么情况下应该使用工厂模式?

:当对象创建逻辑复杂,需要统一管理创建过程,或者需要动态选择具体实现类时。

相关文章
|
15天前
|
设计模式 Java Spring
Java 设计模式之责任链模式:优雅处理请求的艺术
责任链模式通过构建处理者链,使请求沿链传递直至被处理,实现发送者与接收者的解耦。适用于审批流程、日志处理等多级处理场景,提升系统灵活性与可扩展性。
133 2
|
15天前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
167 0
|
3月前
|
设计模式 缓存 Java
Java设计模式(二):观察者模式与装饰器模式
本文深入讲解观察者模式与装饰器模式的核心概念及实现方式,涵盖从基础理论到实战应用的全面内容。观察者模式实现对象间松耦合通信,适用于事件通知机制;装饰器模式通过组合方式动态扩展对象功能,避免子类爆炸。文章通过Java示例展示两者在GUI、IO流、Web中间件等场景的应用,并提供常见陷阱与面试高频问题解析,助你写出灵活、可维护的代码。
|
14天前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
171 35
|
14天前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
133 8
|
6月前
|
设计模式 缓存 安全
【高薪程序员必看】万字长文拆解Java并发编程!(8):设计模式-享元模式设计指南
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的经典对象复用设计模式-享元模式,废话不多说让我们直接开始。
131 0
|
3月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
8月前
|
设计模式 Java 数据安全/隐私保护
Java 设计模式:装饰者模式(Decorator Pattern)
装饰者模式属于结构型设计模式,允许通过动态包装对象的方式为对象添加新功能,提供比继承更灵活的扩展方式。该模式通过组合替代继承,遵循开闭原则(对扩展开放,对修改关闭)。
|
12月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
186 6
|
12月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
162 4