设计模式之-----单例模式

来源:互联网 发布:java分支循环语句 编辑:程序博客网 时间:2024/06/13 14:37

单例模式

原文地址


引言

上篇博客我们介绍了设计模式的六大基本原则,从今天开始我们一起来看几种常见的设计模式,设计模式在代码编写中用途非常广泛,正因为如此,一位优秀的程序员,肯定也是可以灵活运用常见设计模式的。那么今天介绍的就是单例模式

简介

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

使用场景

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

注意

1.构造函数不对外开放,一般为private2.通过一个静态方法,或者每句返回单例类对象。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);    }}

总结

总是单例模式的实现规则多种多样,具体选择哪种方法,还需要根据实际情况进行推敲,如果无法确定使用那种情况的,建议使用枚举,或者静态内部类的方式实现。

1 0