首页 > 设计模式 > 设计模式之单例模式

设计模式之单例模式

2014年11月16日 发表评论 阅读评论

在程序设计中,单例模式是非常常用的一个设计模式,至于有点老夫就不用多说了,肯定有一点比较省内存,但什么的类适合于设置成单例呢?一言以蔽之:

在程序设计中,无状态的类都可以设置成单例。

那么问题来了,什么样的类是无状态的,什么样的类是有状态的呢?其实很简单:

没有数据,也就是说这个类只有方法,没有成员变量。

举个例子:
User类是否可以设置成单例呢?肯定不行,因为User类每一个对应的Id肯定是不同的人,如果设置成单例,数据就乱了;但一般Service层、DAO层的方法呢?这个一般都是一些业务逻辑,只有一些方法,没有数据,所以肯定可以设置成单例,事实上我们这些类如果有Spring托管,那么自然而然这些类就是单例的。

既然单例使用这么多,有点还这么明显,那么怎么设置一个类是单例的呢?根据老夫第一个项目经理Zack的说法,设置一个类成单例的,有两种方法,首先看第一个,传统意义上的单例:


package cn.bridgeli.singleton;

public class Singleton {
    private static volatile Singleton singleton = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (null == singleton) {
            synchronized (Singleton.class) {
                if(null == singleton) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

这个最简单,构造方法设置成私有的,别人就不能new了,想获取实例必须通过getInstance()方法,而这个方法里面是static的,所以这是一个传统意义上的最简单的单例。

除此之外,我们还可以借助于静态内部类的方式实现单利:


package cn.bridgeli.demo.singleton;

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}

第二个,管理意义上的单例
我们自己观察可以发现,这个虽然简单,但我们Spring实现的单例,肯定不是这么实现的,那么他是怎么实现的呢?Spring并没有限制我们自己写的类必须要有一个私有的构造方法,所以管理意义上的单例,并不要一个类有一个私有的构造方法,但他会通过一个BeanFactory产生我们想要的实例,参考代码如下:


package cn.bridgeli.singleton;

import java.util.HashMap;
import java.util.Map;

import cn.bridgeli.justforfun1992.service.UserService;
import cn.bridgeli.justforfun1992.service.impl.UserServiceImpl;

public class BeanFactory {
    private static BeanFactory beanFactory = null;
    private static Map<String, Object> beans = new HashMap<String, Object>();

    private BeanFactory() {
    }

    public static BeanFactory getInstance() {

        if (null == beanFactory) {
            beanFactory = new BeanFactory();
        }
        return beanFactory;

    }

    public static Object getBean(String key) {
        if (!beans.containsKey(key)) {
            if (key.equals("UserService")) {
                UserService userService = new UserServiceImpl();
                beans.put(key, userService);
            }
        }
        return beans.get(key);
    }
}

UserService类


package cn.bridgeli.justforfun1992.service;

public interface UserService {
    void add(User user);
}

UserServiceImpl类

package cn.bridgeli.justforfun1992.service.impl;

import cn.bridgeli.justforfun1992.service.UserService;

public class UserServiceImpl implements UserService {

    @Override
    public void add(User user) {
        System.out.println("saved");
    }

}

所以当我们想获取UserService的实例时,可以通过这个BeanFactory获取,所以我们虽然没有给UserServiceImpl设置私有构造方法,同样也实现了单例,但是这么做也有一点不好,因为没有私有构造方法,所以你禁不住别人 new ,这就要求我们开发人员遵守好规则,大家只能通过getBean()去获取实例,其实我相信有些人也应该看出来了,这个BeanFactory其实是一个工厂,他负责产生我们想要的各种Bean,所以这里面也应用了工厂模式
最后在补充一点:如果我们改造一下getBean()方法,内部实现不是直接new,而是通过读取XML文件,利用反射实例化实例,是不是我们就模拟出来了Spring的IOC?其实很简单,感兴趣的同学可以自己去实现以下,老夫就不赘述了

全文完,如果本文对您有所帮助,请花 1 秒钟帮忙点击一下广告,谢谢。

作 者: BridgeLi,https://www.bridgeli.cn
原文链接:http://www.bridgeli.cn/archives/113
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
  1. mstar
    2014年11月17日18:40 | #1

    就向你学习Java了

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

请输入正确的验证码