大家在使用Windows的时候不知道有没有注意过一个细节,在我们使用任务管理器的时候没有办法同时打开两个,也就是说,它在整个系统中只有唯一的一个实例。
对于系统中的某些类来说,只有一个实例很重要 !
例如:
如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源,如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此,有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
单例模式是一种对象创建型模式。
单例模式确保某一个类只有一个实例,而且自行实例化并向整个例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:
单例模式只包含一个 Singleton(单例角色)类,在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以使用它的唯一实例。
为了防止在外部对其实例化,将其构造函数设计为私有,在单例类内部定义了一个 Singleton类型的静态对象,作为外部共享的唯一实例。
一般情况下单例模式的代码实现如下 👇
package singleton;
/** * @author mengzhichao * @create 2021-11-28-15:47 */
public class Singleton {
private static Singleton instance=null; //静态私有成员变量
//私有构造函数
private Singleton(){
}
//静态共有工厂方法,返回唯一实例
public static Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
为了测试单例类所创建对象的唯一性,可以编写如下客户端测试代码
package singleton;
/** * @author mengzhichao * @create 2021-11-28-15:51 */
public class Client {
public static void main(String[] args) {
Singleton s1=Singleton.getInstance();
Singleton s2=Singleton.getInstance();
System.out.println(s1==s2);
}
}
编译代码并运行,输出结果为:true
在单例模式的实现过程中,需要注意以下几点:
系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
使用单例模式有一个必要条件: 在一个系统中要求一个类只有一个实例时才应当使用单例模式。反过来,如果一个类可以有几个实例共存,就需要对单例模式进行改进,使之成为多例模式。
主要优点在于提供了对唯一实例的受控访问并可以节约系统资源。
其主要缺点在于因为缺少抽象层而难以扩展,且单例类职责过重。
在每一个Java应用程序里面,都有唯一的一个Runtime对象,通过这个Runtime对象,应用程序可以与其运行环境发生相互作用。在JDK中,Runtime类的源代码片段如下:
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
...
}
当我们试图要从 Spring容器中获取某个类的实例时,默认情况下Spring会通过单例模式进行创建,也就是在Spring 的 bean 工厂中这个bean的实例只有一个,代码如下:
<bean id="date" class="java.util.Date" scope="singleton"/>
现使用单例模式模拟该场景。
在单例类IdentityCardNo中除了静态工厂方法外,还可以包含一些其他业务方法﹐如本例中的setIdentityCardNo()方法和 getIdentityCardNo()方法。在工厂方法 getInstance()中,先判断对象是否存在,如果不存在则实例化一个新的对象﹐然后返回;如果存在则直接返回已经存在的对象。
package singletontest;
/** * @author mengzhichao * @create 2021-11-28-16:18 */
public class IdentityCardNo {
private static IdentityCardNo instance = null;
private String no;
private IdentityCardNo() {
}
public static IdentityCardNo getInstance(){
if (instance==null){
System.out.println("第一次办理身份证,分配新号码");
instance=new IdentityCardNo();
instance.setIdentityCardNo("No410111111122222222");
}else {
System.out.println("重复办理身份证,获取旧号码!");
}
return instance;
}
private void setIdentityCardNo(String no){
this.no=no;
}
public String getIdentityCardNo(){
return this.no;
}
}
在客户端测试代码中定义了两个IdentityCardNo类型的对象,通过调用两次静态工厂方法 getInstance()获取对象,然后判断它们是否相等﹔再通过业务方法 getIdentityCardNo()获取封装在对象中的属性号码no值,判断两次no值是否相同。
package singletontest;
/** * @author mengzhichao * @create 2021-11-28-16:26 */
public class Client {
public static void main(String[] args) {
IdentityCardNo no1,no2;
no1=IdentityCardNo.getInstance();
no2=IdentityCardNo.getInstance();
System.out.println("身份证号码是否一致:" + (no1==no2));
String str1,str2;
str1=no1.getIdentityCardNo();
str2=no2.getIdentityCardNo();
System.out.println("第一次号码:"+str1);
System.out.println("第二次号码:"+str2);
System.out.println("内容是否相同:"+str1.equalsIgnoreCase(str2));
System.out.println("对象是否相同:"+ (str1==str2));
}
}
从结果可以看出,两次创建的IdentityCardNo对象内存地址相同,是同一个对象,封装在其中的号码no属性不仅值相等,其内存地址也一致,是同一个成员属性。
学习更多设计模式还请访问:https://blog.csdn.net/weixin_45692705?spm=1011.2124.3001.5343
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_45692705/article/details/121589723
内容来源于网络,如有侵权,请联系作者删除!