前言:软件设计模式( Software Design Pattern ),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。
正确使用设计模式具有以下优点。
1.可以提高程序员的思维能力、编程能力和设计能力。
2.使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,
从而缩短软件的开发周期。
3.使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
设计模式主要可以分为以下三大类:创建型模式,结构型模式,行为型模式
因此本篇文章主要是讲解第一类设计模式之创建型模式之单例模式
保证一个类只有一个实例,并且提供一个访问该全局访问点
优点:
1. 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例 2. 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。 3. 提供了对唯一实例的受控访问。 4. 由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。 5. 允许可变数目的实例。 6. 避免对共享资源的多重占用。
缺点:
1. 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 2. 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 3. 单例类的职责过重,在一定程度上违背了 “ 单一职责原则 ” 。 4. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
1. 网站的计数器,一般也是采用单例模式实现,否则难以同步。 2. 应用程序的日志应用,一般都是单例模式实现,只有一个实例去操作才好,否则内容不好追加显示。 3. 多线程的线程池的设计一般也是采用单例模式,因为线程池要方便对池中的线程进行控制 4. Windows 的(任务管理器)就是很典型的单例模式,他不能打开俩个 5. windows 的(回收站)也是典型的单例应用。在整个系统运行过程中,回收站只维护一个实例。
1. 饿汉式: 类初始化时 , 会立即加载该对象,线程天生安全 , 调用效率高。 2. 懒汉式 : 类初始化时 , 不会初始化该对象 , 真正需要使用的时候才会创建该对象 , 具备懒加载功能。 3. 静态内部方式 : 结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。 4. 枚举单例 : 使用枚举实现单例模式 优点 : 实现简单、调用效率高,枚举本身就是单例,由 jvm 从根本上提供保障! 避免通过反射和反序列化的漏洞, 缺点没有延迟加载。 5. 双重检测锁方式 ( 因为 JVM 本质重排序的原因,可能会初始化多次,不推荐使用 )
饿汉式 : 类初始化时 , 会立即加载该对象,线程天生安全 , 调用效率高。
/**
* @author: dlwlrma
* @data 2024年10月26日 19:50
* @Description: TODO:单例模式之饿汉式
*/
public class Demo1 {
//饿汉式,类初始化时,会立即创建对象,调用效率高,但可能会造成内存的浪费
private static Demo1 demo1=new Demo1();
private Demo1(){
}
public static Demo1 getInstance(){
return demo1;
}
public static void main(String[] args) {
Demo1 demo11=Demo1.getInstance();
Demo1 demo12=Demo1.getInstance();
System.out.println(demo11==demo12);
}
}
1. 懒汉式 : 类初始化时 , 不会初始化该对象 , 真正需要使用的时候才会创建该对象 , 具备懒加载功能。
/**
* @author: dlwlrma
* @data 2024年10月26日 19:52
* @Description: TODO:单例模式之懒汉式
*/
//懒汉式
public class Demo2 {
//类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象。
private static Demo2 demo2;
private Demo2() {
System.out.println("私有Demo2构造参数初始化");
}
public synchronized static Demo2 getInstance() {
if (demo2 == null) {
demo2 = new Demo2();
}
return demo2;
}
public static void main(String[] args) {
Demo2 s1 = Demo2.getInstance();
Demo2 s2 = Demo2.getInstance();
System.out.println(s1 == s2);
}
}
1. 静态内部方式 : 结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
/**
* 静态内部类方式
* @author dlwlrma
* @date 2024/10/26 19:56
* @return null
*/
public class Demo3 {
private Demo3() {
System.out.println("私有Demo3构造参数初始化");
}
public static class SingletonClassInstance {
private static final Demo3 DEMO_3 = new Demo3();
}
// 方法没有同步
public static Demo3 getInstance() {
return SingletonClassInstance.DEMO_3;
}
public static void main(String[] args) {
Demo3 s1 = Demo3.getInstance();
Demo3 s2 = Demo3.getInstance();
System.out.println(s1 == s2);
}
}
1. 枚举单例 : 使用枚举实现单例模式 优点 : 实现简单、调用效率高,枚举本身就是单例,由 jvm 从根本上提供保障! 避免通过反射和反序列化的漏洞, 缺点没有延迟加载。
/**
* @author: dlwlrma
* @data 2024年10月26日 19:57
* @Description: TODO: 使用枚举实现单例模式 优点:实现简单、枚举本身就是单例,由jvm从根本上提供
保障!避免通过反射和反序列化的漏洞 缺点没有延迟加载
*/
public class Demo4 {
public static Demo4 getInstance() {
return Demo.INSTANCE.getInstance();
}
public static void main(String[] args) {
Demo4 s1 = Demo4.getInstance();
Demo4 s2 = Demo4.getInstance();
System.out.println(s1 == s2);
}
//定义枚举
private static enum Demo {
INSTANCE;
// 枚举元素为单例
private Demo4 demo4;
private Demo() {
System.out.println("枚举Demo私有构造参数");
demo4 = new Demo4();
}
public Demo4 getInstance() {
return demo4;
}
}
}
1. 双重检测锁方式 ( 因为 JVM 本质重排序的原因,可能会初始化多次,不推荐使用 )
/**
* @author: dlwlrma
* @data 2024年10月26日 19:59
* @Description: TODO:双重检测锁方式
*/
//双重检测锁方式
public class Demo5 {
private static Demo5 demo5;
private Demo5() {
System.out.println("私有Demo4构造参数初始化");
}
public static Demo5 getInstance() {
if (demo5 == null) {
synchronized (Demo5.class) {
if (demo5 == null) {
demo5 = new Demo5();
}
}
}
return demo5;
}
public static void main(String[] args) {
Demo5 s1 = Demo5.getInstance();
Demo5 s2 = Demo5.getInstance();
System.out.println(s1 == s2);
}
}