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

单例模式

原文地址


引言

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

简介

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

使用场景

确保一个类只有一个对象的场景,避免多个对象消耗过多的资源,或者某种类型的对象只应该只有一个,例如:创建一个对象需要消耗的资源过多,如果访问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);
    }
}

总结

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值