设计模式之单例模式

单例模式保证了在应用中只有一个实例的存在,比如在一个应用中,只需要一个ImageLoader实例。

定义:

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

场景

确保某个类又切只有一个对象的场景,避免产生多个对象耗费过多的资源。当创建一个对象需要消耗的资源过多时,就要考虑用单例设计模式。
如一个公司只有一个ceo,一个应用中只有一个Application

关键点

构造函数不对外开放,private(客户端不能通过new重新创建对象)。
通过静态方法或者枚举返回单例类对象(需要确保线程安全)。
确保单例类的对象有且只有一个。
确保单例对象在反序列化时不会重新创建对象。

饿汉式

声明时初始化

public class Staff{
    public void work(){}
}

public class VP extends Staff{

}

public class CEO extends Staff{
    private static final CEO mCeo= new CEO();

    private CEO(){}

    public static CEO getmCeo{
        return mCeo;
    }
}

其中VP和Staff不是单例的,CEO是单例的,只有一个对象。

懒汉式

第一次调用时初始化

public class Singleton {

    // 1.一个私有的指向自己的静态变量
    private static Singleton instance;

    // 2.私有的构造方法,保证不能从外部创建对象
    private Singleton(){}

    // 3.公开的静态工厂方法,返回该类的唯一实例(当发现没有实例没有初始化的时候才初始化)
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}

优点:初始化才创建
缺点:每次都需要检查同步,消耗资源

Double-checked Locking (DCL)

public class LockSingleton{  
    private volatile static LockSingleton singleton;  
    private LockSingleton(){}  

    //http://www.ibm.com/developerworks/cn/java/j-dcl.html  
    public static LockSingleton getInstance(){  
        if(singleton==null){  
            synchronized(LockSingleton.class){  
                if(singleton==null){  
                    singleton=new LockSingleton(); //非原子性操作 
                }  
            }  
        }  
        return singleton;  
    }  

}

singleton=new LockSingleton();是非原子性操作,分为3个步骤

  1. 给LockSingleton实例分配内存
  2. 调用构造函数;初始化成员字段
  3. 将singleton对象指向非配的内存空间

其中 2 和 3 顺序是未定的,容易引起DCL失效,需要借助volatile关键字解决这个问题

优点:初始化才实例化,效率高
缺点:第一次翻译稍慢

静态内部类

class InternalSingleton{  
    private static class SingletonHolder{  
        private final static  InternalSingleton INSTANCE=new InternalSingleton();  
    }     
    private InternalSingleton(){}  
    public static InternalSingleton getInstance(){  
        return SingletonHolder.INSTANCE;  
    }  
}  

优点:调用时才初始化静态变量INSTANCE,,也有效避免了DCL失效 ,所以推荐使用这种方式。

枚举方式

/** 
 * 《Effective Java》作者推荐使用的方法,优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象 
 */  
enum EnumSingleton{  
    INSTANCE;  
    public void doSomeThing(){  
    }  
} 

反序列化可以通过复写钩子函数:readResolve(),返回单例对象,默认会重新生成一个新的对象。

容器实现

另类的单例实现,将单例类型注入到一个统一的管理类中,再根据key获取对象对应类型的对象。也称为登记式单例

public class SingletonManager {
    private SingletonManager() {
    }

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

    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);
    }

}

Android 中的单例

在android系统中,我们经常会通过Context获取系统的服务,如WindowsManagerService、ActivityManagerService、LayoutInflater等。

 LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

实例代码

DesignPatterns

扩展阅读:

Java Singleton Design Pattern Best Practices with Examples

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值