您的位置:首页 > 科技 > IT业 > 上海门户网站论坛_重庆市有几个区_网站推广的公司_个人怎么做网站

上海门户网站论坛_重庆市有几个区_网站推广的公司_个人怎么做网站

2025/2/22 13:53:13 来源:https://blog.csdn.net/Prince140678/article/details/145743615  浏览:    关键词:上海门户网站论坛_重庆市有几个区_网站推广的公司_个人怎么做网站
上海门户网站论坛_重庆市有几个区_网站推广的公司_个人怎么做网站

单件模式:独一无二的对象,如何优雅实现?

大家好!今天我们来聊聊设计模式中的单件模式(Singleton Pattern)。如果你曾经需要确保一个类只有一个实例,并且这个实例能够被全局访问,那么单件模式就是你的不二之选!本文基于《Head First 设计模式》的单件模式章节,通过生动的故事和 Java 代码示例,带你轻松掌握单件模式的精髓。

在这里插入图片描述


1. 单件模式是什么?

单件模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单件模式的核心思想是控制对象的创建过程,避免重复创建实例,从而节省资源并保证数据的一致性。

适用场景

  • 需要全局唯一的对象,比如配置文件管理器、线程池、数据库连接池等。
  • 需要严格控制实例数量的场景。

2. 单件模式的实现

故事背景

小明开发了一个巧克力工厂系统,系统中有一个巧克力锅炉(ChocolateBoiler)类,用于控制巧克力的生产和填充。由于锅炉是唯一的资源,必须确保系统中只有一个锅炉实例。

问题出现

如果直接通过 new ChocolateBoiler() 创建锅炉对象,可能会导致多个实例被创建,从而引发资源冲突和数据不一致。

解决方案:单件模式

小明决定使用单件模式,确保系统中只有一个锅炉实例。

代码实现

基础版单件模式
public class ChocolateBoiler {// 静态变量,保存唯一实例private static ChocolateBoiler instance;// 私有构造函数,防止外部直接创建实例private ChocolateBoiler() {System.out.println("Creating a new ChocolateBoiler instance");}// 全局访问点public static ChocolateBoiler getInstance() {if (instance == null) {instance = new ChocolateBoiler();}return instance;}// 其他方法public void fill() {System.out.println("Filling the boiler with chocolate");}public void boil() {System.out.println("Boiling the chocolate");}public void drain() {System.out.println("Draining the boiled chocolate");}
}// 客户端代码
public class ChocolateFactory {public static void main(String[] args) {ChocolateBoiler boiler = ChocolateBoiler.getInstance();boiler.fill();  // 输出: Filling the boiler with chocolateboiler.boil();  // 输出: Boiling the chocolateboiler.drain(); // 输出: Draining the boiled chocolate// 再次获取实例ChocolateBoiler boiler2 = ChocolateBoiler.getInstance();System.out.println(boiler == boiler2); // 输出: true,说明是同一个实例}
}
优点
  • 确保一个类只有一个实例。
  • 提供全局访问点,方便使用。
缺点
  • 基础版单件模式在多线程环境下可能会创建多个实例。

3. 多线程环境下的单件模式

问题出现

如果多个线程同时调用 getInstance() 方法,可能会导致多个实例被创建。

解决方案:线程安全的单件模式

方法 1:加锁(synchronized)
public class ChocolateBoiler {private static ChocolateBoiler instance;private ChocolateBoiler() {System.out.println("Creating a new ChocolateBoiler instance");}// 加锁,确保线程安全public static synchronized ChocolateBoiler getInstance() {if (instance == null) {instance = new ChocolateBoiler();}return instance;}// 其他方法public void fill() {System.out.println("Filling the boiler with chocolate");}public void boil() {System.out.println("Boiling the chocolate");}public void drain() {System.out.println("Draining the boiled chocolate");}
}
方法 2:双重检查锁(Double-Checked Locking)
public class ChocolateBoiler {// 使用 volatile 关键字,确保 instance 的可见性private static volatile ChocolateBoiler instance;private ChocolateBoiler() {System.out.println("Creating a new ChocolateBoiler instance");}public static ChocolateBoiler getInstance() {if (instance == null) {synchronized (ChocolateBoiler.class) {if (instance == null) {instance = new ChocolateBoiler();}}}return instance;}// 其他方法public void fill() {System.out.println("Filling the boiler with chocolate");}public void boil() {System.out.println("Boiling the chocolate");}public void drain() {System.out.println("Draining the boiled chocolate");}
}
方法 3:静态内部类(推荐)
public class ChocolateBoiler {// 私有构造函数private ChocolateBoiler() {System.out.println("Creating a new ChocolateBoiler instance");}// 静态内部类,延迟加载且线程安全private static class SingletonHolder {private static final ChocolateBoiler INSTANCE = new ChocolateBoiler();}// 全局访问点public static ChocolateBoiler getInstance() {return SingletonHolder.INSTANCE;}// 其他方法public void fill() {System.out.println("Filling the boiler with chocolate");}public void boil() {System.out.println("Boiling the chocolate");}public void drain() {System.out.println("Draining the boiled chocolate");}
}
优点
  • 线程安全,且性能较高。
  • 延迟加载,只有在第一次调用 getInstance() 时才会创建实例。

4. 单件模式的注意事项

  1. 序列化问题
    如果单件类实现了 Serializable 接口,反序列化时可能会创建新的实例。可以通过重写 readResolve() 方法解决。

    protected Object readResolve() {return getInstance();
    }
    
  2. 反射攻击
    反射可以绕过私有构造函数创建实例。可以通过在构造函数中抛出异常来防止反射攻击。

    private ChocolateBoiler() {if (instance != null) {throw new IllegalStateException("Instance already created");}
    }
    
  3. 单件模式的滥用
    单件模式虽然好用,但不要滥用。过度使用单件模式会导致代码耦合性增加,难以测试和维护。


5. 总结

单件模式是确保一个类只有一个实例的有效方式,适用于需要全局唯一对象的场景。通过本文的讲解和代码示例,相信你已经掌握了单件模式的核心思想和实现方法。在实际开发中,记得根据具体需求选择合适的实现方式,并注意线程安全和反序列化等问题。


互动话题
你在项目中用过单件模式吗?遇到过哪些问题?欢迎在评论区分享你的经验!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com