设计模式演化之单例模式

本文详细介绍了单例模式的设计思想,从定义、场景应用到实现方式,包括懒汉模式、饿汉模式、双重检查锁定模式和内部类单例模式。同时,讨论了单例模式在Kotlin中的实现,并分析了其优缺点,如资源优化、线程安全问题以及适用场景的限制。
摘要由CSDN通过智能技术生成
定义

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

场景

1.我需要写一个文件管理的工具类,来存取本地的一个文件。

public class FileUtil {
    public void saveInfo() {
        System.out.println("save info success");
    }
    
    public void getInfo() {
        System.out.println("get info success");
    }
}

调用

FileUtil fileUtil = new FileUtil();
fileUtil.saveInfo();

2.程序中有大量的存取场景,每次调用都要创建fileUtil对象太麻烦了,我希望FileUtil能提供一个全局获取fileUtil的方法。
实现:在FileUtil新增一个静态方法,用于全局获取。

public class FileUtil {
    
    public static FileUtil getInstance() {
        return new FileUtil();
    }
    ...
}

调用

FileUtil.getInstance().saveInfo();

3.虽然FileUitl提供了全局获取fileUtil对象的方法,但是每次都产生一个新的对象,而且用完就扔了,这样太浪费了。如果这里能只用一个对象就好了。
实现:在FileUtil中新增一个静态变量instance来存储FileUtil对象,需要时直接取instance。

public class FileUtil {
    private static FileUtil instance;
    public static FileUtil getInstance() {
        if (instance == null) {
            instance = new FileUtil();
        }
        return instance;
    }
    ...
}

4.既然FileUtil已经提供了获取对象的方法,我不希望调用处还能通过new来创建它,否则依然会存在多个FileUtil的对象。
实现:将FileUitl的构造方法改为private

public class FileUtil {

    private static FileUtil instance;
    
    private FileUtil() {}
    
    public static FileUtil getInstance() {
        if (instance == null) {
            instance = new FileUtil();
        }
        return instance;
    }
    ...
}

至此,一个常见单例模式就完成了。

优化

上边完成的单例模式称为懒汉模式,它依然会存在缺陷。
1.懒汉模式(线程不安全),第一次调用的时候初始化,不会性能浪费,但第一次加载较慢,且只适用于单线程的环境。

    public class Singleton {
        private static Singleton instance;
        private Singleton(){}
        public static Singleton getInstance() {
            if (instance == null) {
                // 多线程环境下,这里可能被创建多个对象,后边的覆盖前面
                instance = new Singleton();
            }
            return instance;
        }
    }

2.懒汉模式(线程安全),能在多线程中很好的工作,但效率不高。

    public class Singleton {
        private static Singleton instance;
        private Singleton(){}
        // 这里保证线程安全,但是会在每次调用都试图加锁,即使instance已经存在,效率不高。
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

3.双重检查模式(DCL),解决了线程安全和性能的问题,资源利用率较高。

    public class Singleton {
        private Singleton() {}
        private  static Singleton instance;
        public static Singleton getInstance() {
        // 当instance已经存在的时候就不需要加锁了。
            if(instance == null) {
                synchronized(Singleton.class) {
                    if (instance == null) {
                        instance  = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

4.饿汉模式,方法变量全部静态,类加载时直接初始化。但是过早的创建实例,会降低内存的使用效率。
而且如果始终没用到该类,就会造成性能浪费。

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singletion(){}
        public static Singleton getInstance() {
            return instance;
        }
    }

5.内部类单例模式,首次创建的时候会初始化,解决了4中过早创建实例的问题

    public class Singleton {
        private Singleton(){}
        public static Singleton getInstance() {
            reture SingletonHolder.instance;
        }
        private static class SingletonHolder {
            private static final Singleton instance = new Singleton();
        }
    }
Kotlin实现

1.如果单例类能够自己定义,直接使用object代替class即可

object Singleton {
}

2.单例类不能自定义,如Gson

object GsonUitl {
    val gson = Gson()
}
优点

1.类可以自己控制实例化的过程
2.系统中只存在一个对象,可以节约资源
3.避免对共享资源多处占用

缺点

1.不适用于多变复杂的情况
2.没有抽象层,不方便扩展
3.多线程模式下容易引起数据错误
4.长时间不用的话,会被系统回收,执行状态丢失,下次使用会创建全新的对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值