单例模式
引言
上篇博客我们介绍了设计模式的六大基本原则,从今天开始我们一起来看几种常见的设计模式,设计模式在代码编写中用途非常广泛,正因为如此,一位优秀的程序员,肯定也是可以灵活运用常见设计模式的。那么今天介绍的就是单例模式
简介
单例模式:确保每一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
使用场景
确保一个类只有一个对象的场景,避免多个对象消耗过多的资源,或者某种类型的对象只应该只有一个,例如:创建一个对象需要消耗的资源过多,如果访问IO和数据库等资源,这就要使用单例模式。
注意
1.构造函数不对外开放,一般为private
2.通过一个静态方法,或者每句返回单例类对象。
3.确保单例类的对象只有一个,尤其是在多线程的环境下。
4.确保单例对象在反序列化的时候不会重新构建对象
单例模式的实现
一).饿汉模式
class Text {
//构造函数私有化
private Text(){}
private static final Text text = new Text();
//对外暴露,获取单例对象的接口
public static Text getText() {
return text;
}
}
评价:虽然实现了单例模式,一开始类就进行了实例化,即使没有用到此实例,也占用了资源。从而导致了资源的浪费。
二).懒汉模式
class Text {
private Text(){}
private static Text text;
public static synchronized Text getText() {
if(text == null){
text = new Text();
}
return text;
}
评价:虽然满足了上面的问题,只有在使用的时候才进行实例化,但是还有一个问题,就是,当需要使用的时候,需要进行实例化,会降低反应时间,用户体验不佳。
三).Double Check Lock(DCL)实现单例
class Text {
private Text(){}
private static Text text = null;
public static Text getText() {
if(text == null){
synchronized (Text.class){
if(text == null){
text = new Text();
}
}
}
return text;
}
}
简介:很多初学者可能回不明白这个过程,为什么要进行两次判空,我们现在就来介绍,首先我们看这行代码。
text = new Text();
其实上行代码并不是一个原子操作,也就是说不是一步完成的。大概做了以下几步。
1.给text的实例分配内存。
2.调用Text()的构造函数,初始化成员字段。
3.将text对象,指向分配的内存空间,(此时的text才不是null)
为了确保1-2-3执行顺序的不确定,所以使用了以上操作,当然在JDK1.5之后就使用volatile关键词就可以了。
四).静态内部类实现单例
简介:DCL在一定程度上解决了资源消耗,多余的同步,线程安全等问题,但是,他还是会在某种情况下出现问题,这个问题被称为双重检查锁定(DCL)失效,
class Text {
private Text(){}
public static Text getText() {
return TextHolder.text;
}
//静态内部类
private static class TextHolder{
private static final Text text = new Text();
}
}
评价:当第一次加载的时候不会对Text进行实例化,只有当第一次调用getText()的时候才会倒置虚拟机加载TextHolder类,然后进行对象的实例化,这种方式不仅解决了资源浪费的问题,还解决了线程安全,也能够保证单例对象的唯一性,同事延迟了单例的实例化,所以这是推荐的一种方式。
五).枚举实现单例
简介:枚举实现单例是推荐的方法,有以下好处
1.线程安全
2.不会因为序列化而产生新实例
3.防止反射攻击
public enum Text {
INSTANCE;
public void doSomething(){
System.out.print("do sth.");
}
}
六).使用容器的方式实现单例
简介:这是一种将多个单例类注入到一个统一打管理容器中,给每个单例类设置相应的Key,然后保存到容器中,需要的时候再取出。
public class Text {
private static Map<String,Object> objectMap = new HashMap<String, Object>();
private Text(){}
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);
}
}
总结
总是单例模式的实现规则多种多样,具体选择哪种方法,还需要根据实际情况进行推敲,如果无法确定使用那种情况的,建议使用枚举,或者静态内部类的方式实现。
作者:MyLoveyaqiong 发表于2017/1/1 0:37:30 原文链接
阅读:32 评论:0 查看评论