java的23种设计模式06-创建型模式05-单例

一、定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式(Singleton)的目的是为了保证在一个进程中,某个类有且仅有一个实例。

因为这个类只有一个实例,因此,自然不能让调用方使用new Xyz()来创建实例了。

所以,单例的构造方法必须是private,这样就防止了调用方自己创建实例,但是在类的内部,是可以用一个静态字段来引用唯一创建的实例的:

java 复制代码
public class Singleton {
    // 静态字段引用唯一实例:
    private static final Singleton INSTANCE = new Singleton();

    // private构造方法保证外部无法实例化:
    private Singleton() {
    }
}

外部调用方如何获得这个唯一实例?

答案是:

1、提供一个公共静态方法,直接返回实例:

java 复制代码
public class Singleton {
    // 静态字段引用唯一实例:
    private static final Singleton INSTANCE = new Singleton();

    // 通过静态方法返回实例:
    public static Singleton getInstance() {
        return INSTANCE;
    }

    // private构造方法保证外部无法实例化:
    private Singleton() {
    }
}

2、直接把static变量暴露给外部:

java 复制代码
public class Singleton {
    // 静态字段引用唯一实例:
    public static final Singleton INSTANCE = new Singleton();

    // private构造方法保证外部无法实例化:
    private Singleton() {
    }
}

所以,单例模式的实现方式很简单:

  • 只有private构造方法,确保外部无法实例化;
  • 通过private static变量持有唯一实例,保证全局唯一性;
  • 通过public static方法返回此唯一实例,使外部调用方能获取到实例。

【注意】:

该方式有一个潜在问题:即序列化和反序列化会绕过普通类的private构造方法从而创建出多个实例。

二、示例

一种实现Singleton的方式是利用Java的enum,因为Java保证枚举类的每个枚举都是单例,所以我们只需要编写一个只有一个枚举的类即可:

java 复制代码
public enum World {
    // 唯一枚举:
	INSTANCE;

	private String name = "world";

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

枚举类也完全可以像其他类那样定义自己的字段、方法,这样上面这个World类在调用方看来就可以这么用:

java 复制代码
String name = World.INSTANCE.getName();

使用枚举实现Singleton避免了实现Singleton的一个潜在问题:

即序列化和反序列化会绕过普通类的private构造方法从而创建出多个实例。

那我们什么时候应该用Singleton呢?

实际上,很多程序,尤其是Web程序,大部分服务类都应该被视作Singleton,如果全部按Singleton的写法写,会非常麻烦,所以,通常是通过约定让框架(例如Spring)来实例化这些类,保证只有一个实例,调用方自觉通过框架获取实例而不是new操作符:

java 复制代码
@Component // 表示一个单例组件
public class MyService {
    ...
}

因此,除非确有必要,否则Singleton模式一般以"约定"为主,不会刻意实现它。

三、小结

Singleton模式是为了保证一个程序的运行期间,某个类有且只有一个全局唯一实例;

Singleton模式既可以严格实现,也可以以约定的方式把普通类视作单例。

相关推荐
滴啦嘟啦哒20 小时前
【具身笔记】【Piper+PI0.5】三、探究失败原因
笔记·python·vla·具身
白露与泡影20 小时前
Spring AI Alibaba -- 文生图、文生音及向量化
java·人工智能·spring
滕州市燕猫虎计算机科技工作室个体工商户20 小时前
Java,Java NIO,Java NIO2,Java AIO,AsynchronousServerSocketChannel
java·开发语言·nio·aio·nio2
学长毕设20 小时前
基于springboot的社会志愿者管理系统-附源码
java·spring boot·后端
1314lay_100720 小时前
MESSAGE ‘採購單不存在‘(005) TYPE ‘S‘ DISPLAY LIKE ‘E‘.
经验分享·笔记
木头科技20 小时前
【AI 工程化第十六篇】Spring AI 多模态 RAG 实战:图片、扫描件、表格与图文证据链
java·人工智能·spring
说实话起个名字真难啊21 小时前
Git常用小问题笔记
笔记·git·elasticsearch
驭渊的小故事21 小时前
从 JVM 底层看泛型:泛型擦除、Signature 属性与 Super Type Token 模式
java·开发语言·jvm
菜鸟小杰子21 小时前
手动修改 Spring Boot 嵌套 JAR 包:大包小包隔离打包实战
java·jar
计算机编程-吉哥21 小时前
计算机毕业设计 基于 SpringBoot + Vue 的剧本杀系统 Java毕业设计【任务书、开题报告、中期报告、论文、源码】
java·vue.js·spring boot·毕业设计·课程设计·计算机毕业设计选题