开发者模式之—-单例模式

开发者模式之—-单例模式

—前序:本文为《Androdi源码及开发模式》的学习笔记。

定义:

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

使用情景:

确保某个类有且只有一个对象的情景,避免每次使用都重复创建对象,而消耗过多资源。例如,创建一个对象需要消耗的资源过多,如要访问IO或数据库资源,这是就要考虑单例模式。

详细介绍:

通过将单例类的构造函数私有化,使得客户端代码不能通过new的形式手动构造单例类的对象。单例类会暴露一个公有的静态方法,客户端需要调用这个这个静态方法获取到单例类的唯一对象吗,在获取到这个单例对象的过程中需要确保线程安全,也就是在多线程的环境下构造单例类的对象也是有且只有一个,这也是单例模式中最困难的地方。

关键点:

  1. 构造函数不对外开放,一般为private;
  2. 通过一个静态方法或者枚举返回单例类对象;
  3. 确保单例类的对象有且只有一个,尤其是在多线程的环境下;
  4. 确保单例类对象在反序列化时不会重新构造对象。
UML图:

单例模式uml图


单例模式的写法一般有以下几种:
第一种、最普通的单例模式(饿汉模式):

在类加载时就进行初始化,不管方法有没有被调用。

public class SingleTon1 {

    private static final SingleTon1 instance = new SingleTon1();

    private SingleTon1() {
    }

    public SingleTon1 getInstance() {
        return instance;
    }
}
第二种:懒汉模式:

利用synchronize 进行同步,在getInstance第一次调用时进行初始化,在多线程下利用synchronize保证单例对象的唯一性,但是这样每次执行都会执行进行同步,消耗不必要的资源
优点:单例只有使用时才会被实例化,在一定程度上节约了资源
缺点:第一次加载时需要及时地进行实例化,反应相当稍慢,最大的问题是每次调用getInstance都进行同步,造成不必要的开销。
*这种模式不建议使用!

public class SingleTon2 {

    private static SingleTon2 instance;


    private SingleTon2() {
    }


    public static synchronized SingleTon2 getInstance() {
        if (instance == null)
            instance = new SingleTon2();
        return instance;
    }
}
第三种:Double Check Lock(DCL)双重判空实现单例

对instance进行了两次判空,第一次判空是为了避免不必要的同步,相当Single2的懒汉模式的每次同步优化了很多, 第二次判空是为了在null的情况下创建实例,
* 优点:第一次执行getInstance时单例对象才被实例化,效率高
* 缺点:第一次加载时反应稍慢

public class SingleTon3 {

    private static SingleTon3 singleTon3;

    public SingleTon3() {
    }

    public static SingleTon3 getInstance() {
        if (singleTon3 == null) {
            synchronized (SingleTon3.class) {
                if (singleTon3 == null)
                    singleTon3 = new SingleTon3();
            }

        }
        return singleTon3;
    }
}
第四种:静态内部类单例模式

第一次加载SingleTon类时不会初始化singleTon4,只有调用getInstance方法时才被初始化。这种方法不仅确保线程安全,也能够保证单例对象的唯一性,
* 同时也延迟了单例的实例化,这是最推荐使用的单例模式实现方式

public class SingleTon4 {

    public SingleTon4() {
    }

    public static SingleTon4 getInstance() {
        return SingleTonHolder.singleTon4;
    }

    private static class SingleTonHolder {
        public static SingleTon4 singleTon4 = new SingleTon4();
    }
}
第五种:枚举实现单例

默认枚举实例的创建是安全的,并且在任何情况下他都是一个单例

public enum SingleTon5 {

    INSTANCE;

    public void doSomething() {
        System.out.print("do sth.");
    }
}
第六种:使用容器实现单例模式

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

public class SingleTonManager6 {

    private static HashMap<String, Object> objMap = new HashMap<>();

    public SingleTonManager6() {
    }

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

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

单例模式的优点:

1、由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建销毁时,而且对象的创建和销毁又无法优化,单例模式的优势就会十分明显。
2、避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对用一个资源文件的同时写操作。
3、单例模式可以在系统设置全局的访问点,优化和共享资源范围。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值