Kotlin速通设计模式之单例模式

1.什么是单例

单例或称单例设计模式(Singleton Design Pattern),23种设计模式之一创建型模式的一种,使用频率极高,是必须了解的设计模式之一;单例的职责概括起来很简单那就是**保证某一个类只能有一个实例以供全局使用

2.为什么需要单例

单例类的特殊性使得我们可以在一定的程度上避免了频繁创建销毁对象时所带来的开销全局访问到的对象都是同一个(如实现网络请求、数据库操作等)这也就代表着可以实现资源的共享避免多个实例竞争使用同一资源等等。

3.如何实现单例

实现单例大致可以分为以下这几种:

  • 饿汉模式
  • 懒汉模式
  • 静态内部类创建
  • Kotlin实现
  • 枚举类 下面,我将一一举例如何实现一个单例类(为了方便类名统一称为Singleton

饿汉模式

public class Singleton {  
    //饿汉模式  
    private static Singleton instance = new Singleton();  
    //不暴露无参构造  
    private Singleton() {  
    }  
    //获取实例  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

饿汉模式顾名思义嘛,一上来就直接将实例创建完成,利用JVM特性使得该过程是线程安全的,但是缺点还是显而易见的,静态变量不能实现懒加载,造成了资源上的浪费

懒汉模式

懒汉模式相比于饿汉模式就突出在上即是延迟初始化,但是实现方式的不同决定了懒汉模式是否是线程安全的。

平平无奇懒汉
public class Singleton {  
    //懒汉模式  
    private static Singleton instance;  
    //不暴露无参构造  
    private Singleton() {  
    }  
    //获取实例  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
        return instance;  
    }  
}

看的出来,懒汉模式下的单例可以在我们需要使用的时候才初始化单例对象,但是上述方法中存在一个问题,那就是在多线程并发的情况下不能保证创建单例对象的唯一性(线程不安全)。

线程安全懒汉
public class Singleton {  
    //懒汉模式(线程安全)  
    private volatile static Singleton instance; //volatile修饰 保证修改的值会立即被更新到主存  
    private Singleton() {}  

    //双重检查  
    public static Singleton getInstance() {  
        //第一次判空
        if (instance == null) {  
        synchronized (Singleton.class) {  
            //第二次判空
            if (instance == null) {  
            instance = new Singleton();  
               }  
            }  
        }  
        return instance;  
    }  
}

在该方式下,我们使用volatile关键字确保了单例对象的共享可见,其中两次的判空起到的作用也不同,第一次判空是判断是已经否存在单例对象,第二次判空配合synchronized确保单例对象的一致性,保证了线程安全

静态内部类

public class Singleton {  
    private Singleton() {}  
    //向外暴露获取实例的方法  
    public static Singleton getInstance() {  
        return InnerSingleton.instance;  
    }  
    //内部类  
    private static class InnerSingleton {  
        private static final Singleton instance = new Singleton();  
    }  
}

静态内部类可以说是结合了饿汉模式和懒汉模式的优点,利用了类初始化的时候,不会去初始化静态内部类,而是只有在你去调用了 getInstance()方法的时候,才选择初始化,同时利用JVM特性也保证了单例对象创建的线程安全

Kotlin中的单例

object SingletonKt {  
//.....  
}

你没看错,Kotlin实现单例仅仅只需要将class替换为object就可以了,为什么能这么轻松的实现呢?我们反编译一下就能看出其实也是使用了静态内部类的方式实现的单例。

public final class SingletonKt {  
    @NotNull  
    public static final SingletonKt INSTANCE;  

    private SingletonKt() {  
    }  

    static {  
        SingletonKt var0 = new SingletonKt();  
        INSTANCE = var0;  
    }  
}

枚举

最后一个就是我们的枚举类,枚举是一种特使的单例,它可以保证单例无法被反射破坏。

public enum Singleton {  
INSTANCE  
}

4.如何破坏单例

反射

利用反射可以破坏单例:

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {  
  
    //获取Singleton类的字节码对象  
    Class clazz = Singleton.class;  

    //获取私有无餐构造对象  
    Constructor constructor = clazz.getDeclaredConstructor();  

    //取消访问检查  
    constructor.setAccessible(true);  

    //创建singleton对象  
    Singleton instance1 = (Singleton) constructor.newInstance();  
    Singleton instance2 = (Singleton) constructor.newInstance();  

    System.out.println(instance2);  
    System.out.println(instance1);  
}

结果:

singleton.Singleton@723279cf

singleton.Singleton@10f87f48

可以看到利用反射成功破坏了单例。

5.总结

  • 使用单例的目的是为了保证其对象的全局唯一性
  • 设计单例的时候需要考虑到懒加载以及线程安全问题
  • 使用Kotlin中object可以快速创建单例类
  • 单例是可以被破坏的(利用反射等其他方法)

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值