应用最广的模式——单例模式

#1.单例模式定义

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

#2.单例模式使用场景

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时要考虑使用单例模式。

#3.单例模式UML图

这里写图片描述

#4.单例模式实现

将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个获取过程中必须保证线程安全、防止反序列化导致重新生成实例对象等问题。

##4.1饿汉模式

public class Singleton {
    private static final Singleton singleton = new Singleton();
    
    private Singleton(){};
    
    public static Singleton getInstance(){
        return singleton;
    };
}

##4.2懒汉模式

public class Singleton {
    private static Singleton instance ;

    private Singleton(){};

    public static synchronized Singleton getInstance(){
        if(instance!=null){
            instance = new Singleton();
        }
        return instance;
    };
}

##4.3Double Check Lock(DCL)实现单例(推荐使用)

DCL方式实现单例模式的优点是既能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用getInstance不进行同步锁。但是在高并发场景比较复杂或者低于JDK6版本下使用可能会有DCL失效。

public class Singleton {
    private volatile static Singleton sInstance = null;//volatile关键字确保instance对象每次都是总主内存中读取,volatile在JDK6以后才有的关键字

    private Singleton(){};

    public static synchronized Singleton getInstance(){
        if(sInstance ==null){//这一步判断为了避免不必要的同步
            synchronized (Singleton.class){
                if(sInstance == null){//这一步判断为了在null情况下创建实例
                    sInstance = new Singleton();
                }
            }
        }
        return sInstance;
    };
}

##4.4静态内部类单例模式(推荐)

public class Singleton {
    private Singleton(){};

    public static  Singleton getInstance(){
        return SingletonHolder.sInstance;
    };

    public static class SingletonHolder{
        private static final Singleton sInstance = new Singleton();
    }
}

##4.5枚举单例

public enum SingletonEnum {
    INSTANCE;
    public void doSomething(){
        System.out.println("do sth.");
    }
}

##4.6使用容器管理单例模式

在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。

public class SingletonManager {
    private static Map<String,Object> objectMap = new HashMap<String,Object>();

    private SingletonManager(){}

    public static void registerService(String key,Object instance){
        if(!objectMap.containsKey(key)){
            objectMap.put(key,instance);
        }
    }

    public static Object getService(String key){
        return objectMap.get(key);
    }
}

#5.总结

单例模式是运用频率很高的模式,但是,由于客户端通常没有高并发的情况,因此,选择哪种实现方式并不会有太大的影响。即便如此,处于效率考虑,推荐使用DCL和静态内部类方式实现单例。

优点

  1. 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
  2. 由于单例模式只生成一个实例,所以,减少了系统的性能开销,当一个对象的产生需要较多的资源时,如读取配置、产生其他依赖时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
  3. 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。

缺点

  1. 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
  2. 单例对象如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。

备注:读《Android源码设计模式解析与实践》笔记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值