目录
单例模式【Singleton Pattern】结构?特点?应用场景?优点与缺点?单例模式实现?
单例模式(Singleton Pattern) 是这些设计模式中的一种,它提供了一种创建对象的最佳方式,确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这种模式在需要严格控制资源访问、管理全局状态或实现共享资源访问时非常有用。
核心思想
单例模式的核心思想是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。它通过私有化构造函数和拷贝构造函数(以及赋值操作符,如果适用),并提供一个静态方法来创建和返回类的唯一实例,来实现这一目标。
单例模式结构
私有静态成员变量:用于存储类的唯一实例。
私有构造函数:防止外部代码通过new关键字直接创建类的实例。
私有拷贝构造函数和赋值操作符(如果适用):防止通过拷贝来创建新的实例。
公有静态方法:提供一个全局访问点来获取类的唯一实例。该方法在实例不存在时创建实例,如果实例已存在则直接返回该实例。
单例模式的特点
全局访问:可以通过一个全局访问点来获取类的唯一实例。
严格控制实例数量:确保类只有一个实例,并提供对该实例的全局访问。
懒汉模式与饿汉模式:单例模式的实现可以分为懒汉式和饿汉式,主要区别在于实例的创建时机。
单例模式应用场景
(1)当类需要控制自己的实例化,确保只有一个实例存在时。
(2)当全局访问点需要被多个类共享时,如配置文件的读取器、数据库连接池等。
(3)当资源访问需要被严格控制时,如打印机、线程池等。
单例模式的优点与缺点
优点
(1)控制资源访问
确保全局只有一个实例,从而可以严格控制对资源的访问。
(2)减少内存开销
避免了频繁创建和销毁实例所带来的性能开销。
(3)简化配置
在单例模式下,全局只有一个配置点,便于管理和维护。
(4)便于共享数据
单例模式提供了全局访问点,使得多个类可以方便地共享数据。
缺点
(1)扩展性差
单例模式对类的扩展性有一定影响,因为它限制了类的实例化方式。
(2)测试困难
在单元测试中,由于单例模式的全局唯一性,可能会导致测试之间的相互影响,增加测试难度。
(3)滥用可能导致问题
如果过度使用单例模式,可能会导致系统结构变得复杂,增加理解和维护的难度。
(4)多线程环境下需要特别注意线程安全
懒汉式单例模式在多线程环境下需要加锁来保证线程安全,这可能会引入性能问题。
单例模式实现
1、先定一个皇帝
懒汉模式
package com.uhhe.common.design.singleton;
/**
* 中国的历史上一般都是一个朝代一个皇帝,有两个皇帝的话,必然要PK出一个皇帝出来【懒汉模式】
*
* @author nizhihao
* @version 1.0.0
* @date 2023/2/27 9:52
*/
public class Emperor {
/**
* 定义一个皇帝放在那里,然后给这个皇帝名字【懒汉模式】
*/
private static Emperor emperor;
private Emperor() {
// 世俗和道德约束你,目的就是不让你产生第二个皇帝
}
/**
* 提供全局访问点
*/
public static Emperor getInstance() {
// 如果皇帝还没有定义,那就定一个
if (emperor == null) {
// 加锁,哪个资源被共享,就加哪个
synchronized (Emperor.class) {
// 双重判断
if (emperor == null) {
emperor = new Emperor();
}
}
}
return emperor;
}
/**
* 皇帝叫什么名字呀
*/
public void emperorInfo() {
System.out.println("我就是皇帝某某某....");
}
}
饿汉模式
package com.uhhe.common.design.singleton;
/**
* 通用单例模式【饿汉模式】
*
* @author nizhihao
* @version 1.0.0
* @date 2023/2/27 10:03
*/
@SuppressWarnings("all")
public class SingletonPattern {
private static final SingletonPattern SINGLETON_PATTERN = new SingletonPattern();
/**
* 限制住不能直接产生一个实例
*/
private SingletonPattern() {
}
public synchronized static SingletonPattern getInstance() {
return SINGLETON_PATTERN;
}
}
2、定义大臣
package com.uhhe.common.design.singleton;
/**
* 大臣是天天要面见皇帝,今天见的皇帝和昨天的,前天不一样那就出问题了!
*
* @author nizhihao
* @version 1.0.0
* @date 2023/2/27 9:56
*/
public class Minister {
/**
* 单例模式【Singleton Pattern】
*
* 大臣天天见到的都是同一个皇帝,不会产生错乱情况,反正都是一个皇帝,是好是坏就这一个
* 只要提到皇帝,大家都知道指的是谁,清晰,而又明确。问题是这是通常情况
* 还有个例的,如同一个时期同一个朝代有两个皇帝,怎么办?
*
* 单例模式很简单,就是在构造函数中多了加一个构造函数,访问权限是 private 的就可以了,这个模
* 式是简单,但是简单中透着风险,风险?什么风险?在一个 B/S 项目中,每个 HTTP Request 请求到 J2EE
* 的容器上后都创建了一个线程,每个线程都要创建同一个单例对象,怎么办?
* 写一个通用的单例程序, 分析一下:
*/
public static void main(String[] args) {
Emperor emperor;
//第一天
emperor = Emperor.getInstance();
//第一天见的皇帝叫什么名字呢?
emperor.emperorInfo();
//第二天
emperor = Emperor.getInstance();
emperor.emperorInfo();
//第三天
emperor = Emperor.getInstance();
emperor.emperorInfo();
//三天见的皇帝都是同一个人,荣幸吧!
}
}