二十三种设计模式之单例模式

概念介绍

一个类只有一个实例,且该类能自行创建这个实例的一种模式。

例如:多线程中的线程池、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、等常常被设计成单例。

特点

  • 单例类只有一个实例对象

  • 该单例对象必须由单例类自行创建

  • 单例类对外提供一个访问该单例的全局访问点

优劣势

优势
  • 在应用场景中,某类只要求生成一个对象的时候。

  • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如数据库的连接池等。

  • 当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。

劣势
  • 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。

  • 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。

  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

实现单例模式的八种方式

  • 1、饿汉式(静态常量)

  • 2、饿汉式(静态代码块)

  • 3、懒汉式(线程不安全)

  • 4、懒汉式(线程安全,同步方法)

  • 5、懒汉式(线程安全,同步代码块)

  • 6、双重检查

  • 7、静态内部类

  • 8、枚举

类图

类图

代码示例

饿汉式(静态常量)
/**
 * @author yulecha
 * @version 1.0.0
 * @ClassName SingletonEH.java
 * @Description 饿汉式
 * @createTime 2019年10月17日 14:45:00
 */
public class SingletonEH {

    /**
     * 本类内部创建对象实例
     */
    private final static SingletonEH instance = new SingletonEH();

    /**
     * 构造器私有化,防止外部通过 new 的方式创建对象
     */
    private SingletonEH() {

    }

    /**
     * 提供一个公有的静态方法,返回实例对昂
     * @return
     */
    public static SingletonEH getInstance() {
        return instance;
    }

}
/**
 * @author yulecha
 * @version 1.0.0
 * @ClassName SingletonEHTest.java
 * @Description 测试单例模式(饿汉式)
 * @createTime 2019年10月17日 14:48:00
 */
public class SingletonEHTest {

    @Test
    public void getInstanceTest() {
        SingletonEH eh1 = SingletonEH.getInstance();
        SingletonEH eh2 = SingletonEH.getInstance();

        // 测试通过(比较内存地址是否相同)
        assertThat(eh1, equalTo(eh2));

        // 测试通过(比较 hashCode 是否相同)
        assertThat(eh1.hashCode(), equalTo(eh2.hashCode()));
    }

}
懒汉式(线程不安全)
/**
 * @author yulecha
 * @version 1.0.0
 * @ClassName SingletonLH.java
 * @Description 懒汉式(线程不安全)
 * @createTime 2019年10月17日 15:10:00
 */
public class SingletonLH {

    /**
     * 定义一个 SingletonLH 类型的属性 instance
     */
    private static SingletonLH instance;

    /**
     * 构造器私有话,防止外部通过 new 的方式创建对象
     */
    private SingletonLH() {

    }

    /**
     * 提供一个公有的静态方法,当使用到该方法时,才去创建 instance
     * @return
     */
    public static SingletonLH getInstance() {
        if (instance == null) {
            instance = new SingletonLH();
        }
        return instance;
    }

}
/**
 * @author yulecha
 * @version 1.0.0
 * @ClassName SingletonLHTest.java
 * @Description 单例模式测试(懒汉式)
 * @createTime 2019年10月17日 15:14:00
 */
public class SingletonLHTest {

    @Test
    public void getInstanceTest() {
        SingletonLH ln1 = SingletonLH.getInstance();
        SingletonLH lh2 = SingletonLH.getInstance();

        // 测试通过(比较内存地址是否相同)
        assertThat(ln1, equalTo(lh2));

        // 测试通过(比较 hashCode 是否相同)
        assertThat(ln1.hashCode(), equalTo(lh2.hashCode()));
    }

}
懒汉式(线程安全,同步方法)
/**
 * @author yulecha
 * @version 1.0.0
 * @ClassName s.java
 * @Description 懒汉式(线程安全)
 * @createTime 2019年10月17日 15:21:00
 */
public class SingletonLH {

    /**
     * 定义一个 SingletonLH 类型的属性 instance
     */
    private static SingletonLH instance;

    /**
     * 构造器私有话,防止外部通过 new 的方式创建对象
     */
    private SingletonLH() {}

    /**
     * 提供一个公有的静态方法,当使用到该方法时,才去创建 instance
     * 加了锁,
     * @return
     */
    public static synchronized SingletonLH getInstance() {
        if (instance == null) {
            instance = new SingletonLH();
        }
        return instance;
    }
}

总结

单例模式大家都普遍很熟悉,实现起来也很简单。一般点的面试题要求就是手写单例模式,饿汉式和懒汉式均可,需要注意的是懒汉式线程是否安全。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值