设计模式之单例模式

设计模式之单例模式

单例,顾名思义,就是指在系统的运行过程中某一个类只有唯一一个对象存在。单例模式,就是实现这样一种方式的一个设计模式。

常见的单例场景

  • windows系统的任务管理器、回收站
  • Servlet中的ServletContext
  • spring中的默认bean对象

优势

  • 由于系统中只存在一个该类型的对象,减少系统的开销,特别是当创建该对象所消耗的资源比较多,但是内容却是一样的时候,单例的优势就非常明显了。
  • 作为全局的资源访问点,减少出错的概率,尤其是在并发环境下

常见的单例写法

所有的单例的写法都有非常明显的特征,那就是构造器私有化,就是防止对象被其他类创建。由类自己创建对象,并且对外提供获得该对象的方法,从而实现单对象,根据创建对象方法的不同,可以有以下几种表现形式

饿汉形式

所谓的饿汉形式,其实就是指对象在类被加载的时候就被创建,具体过程如下所示。

/**
 * 单例模式的饿汉形式
 * @author xuhuanfeng
 *
 */

class TaskManager{

    // 私有化构造器
    private TaskManager(){}

    // 静态属性,在类被加载的时候就会进行初始化,也就是创建该对象
    private static TaskManager taskManager = new TaskManager();

    // 对外的访问方法,用于获得对象
    public static TaskManager getInstance(){
        return taskManager;
    }
}

对应的测试类如下

    @Test
    public void testTaskManager() {

        TaskManager taskManager1 = TaskManager.getInstance();
        TaskManager taskManager2 = TaskManager.getInstance();
        System.out.println("obj one " + taskManager1);
        System.out.println("obj two " + taskManager2);
    }

输出的结果为

obj one cn.xuhuanfeng.sigleton.TaskManager@15db9742
obj two cn.xuhuanfeng.sigleton.TaskManager@15db9742

从上面我们可以看到,类TaskManager仅产生一个对象。

饿汉方式看起来非常直观,代码书写起来也非常方便,但是,这种方式的优缺点却非常明显

  • 优点:由于类被加载的时候对象就已经创建好了,具有天然的线程安全性

  • 缺点:当不需要该类的时候,系统依旧会加载该类,造成资源的浪费,也就是无法做到延迟加载

懒汉形式

所谓的懒汉形式,就是指当需要对象的时候才创建对象,也就是延迟加载,具体过程如下所示

class TaskManager {

    // 私有化构造器
    private TaskManager() {
    }

    // 静态属性,但是这里不进行初始化,也就是加载的时候其值会默认为null
    private static TaskManager taskManager;

    // 由于调用方法的时候,可能会发生并发现象,所以这里需要使用synchronized进行锁定
    public static synchronized TaskManager getInstance() {
        if (taskManager == null) {
            taskManager = new TaskManager();
        }
        return taskManager;
    }

}

对应的测试类同上,这里省略不写

输出的结果如下所示

obj one cn.xuhuanfeng.sigleton.TaskManager@5010be6
obj two cn.xuhuanfeng.sigleton.TaskManager@5010be6

懒汉方式看起来跟饿汉形式非常接近,主要区别在于对象创建的时间,也正是由于这个不同,其优缺点也比较明显

  • 优点:只有当需要的时候才会创建对象,做到了延迟加载
  • 缺点:为了保证获得的对象唯一,必须对访问的方法进行加锁,会带来一定的资源消耗

静态内部类形式

所谓的静态内部类是指,利用静态内部类只有在被调用的时候才会被加载的特性,同时,类的静态属性在类被加载时会自动初始化,实现延迟加载,具体过程如下

class TaskManager {

    // 私有化构造器
    private TaskManager(){}

    // 私有的静态内部类
    private static class Task {
        // 私有的静态属性,当被加载时会自动初始化
        private static TaskManager taskManager = new TaskManager();
    }

    // 对外的访问方法,用于获得对象
    public static TaskManager getInstance() {
        return Task.taskManager;
    }
}

对应的测试类同上,这里省略不写

结果如下所示

obj one cn.xuhuanfeng.sigleton.TaskManager@5010be6
obj two cn.xuhuanfeng.sigleton.TaskManager@5010be6

可以看到,通过这种方式,可以实现单例对象,虽然思路比较绕,但是这种实现方式的优势比前面两个明显

  • 优点:实现延迟加载,同时由于是在加载时进行初始化,所以具有天然的线程安全性
  • 缺点:实现思路比较绕,理解起来比较难

枚举类形式

枚举类的实现,不过这种方面目前笔者只知道其写法,还未理解其原理,所以无法做其他解释,实现代码如下

/**
 * 单例模式的枚举类型实现
 * @author xuhuanfeng
 *
 */
enum  TaskManager{
    INSTANCE;
    // 可以增加其他方法
}

测试类同上

可以看到,这种方式非常简便,而且据网友的介绍,这种方式是比较好的一种方式,笔者正在努力弄懂。

今天学习了Enum类型之后,对上面的定义方式也比较清楚了,上面定义的方式实际上是利用Enum类型所定义出来的对象本身就是静态常量的特性,而且是对应该类型的一个对象,而且可以根据需要增加新方法等实现的,关于Enum可以参见笔者的Enum学习笔记

总结

本节介绍了单例模式及其作用,以及常见的实现单例模式的几种方式,其中静态内部类以及枚举类是实现单例模式比较好的两种做法,也是比较推荐的做法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值