首页 > 代码库 > Java项目(5)——单例模式的应用与研究

Java项目(5)——单例模式的应用与研究

       单例模式是很别致的一个模式,很少有人拿它跟其他模式相比,因为,单例模式很简单,很特别,作用就是保证一个类有唯一一个实例,并让一个全局变量使得它能被访问.而保证这个类只被实例化一次的办法就是把构造函数变为私有的,除了它自己都不能new新对象,然后把实例化的过程写在类自身的公有方法里,是否new新对象只有它自己判断决定,已经有了一个实例就直接返回已存在的对象,没有就new一个新实例.其他类想实例化一个对象时调这个公有方法.

  • 饿汉式(预先初始化对象
 //饿汉式
Class XmlConfigReader{
	private static XmlConfigReader instance=new XmlConfigReader();
	private XmlConfigReader(){
	}
	public static XmlConfigReader getInstance(){
		return instance;
	}
}
  • 懒汉式(延迟初始化对象)

  //懒汉式(延迟加载lazy)
Class XmlConfigReader{   
	 private static XmlConfigReader instance =null;
	    public static synchronized XmlConfigReader getInstance(){
			if(instance==null){
				instance=new XmlConfigReader();
			}
			return instance;
		}
}


    我们常常听到"Double-Check Locking""双重锁定"的概念,这是因为还有一种加锁方式,即使用Lock.

Class XmlConfigReader{
	 private static XmlConfigReader instance;
	private static readonly object syncRoot=new object();
	private XmlConfigReader(){
	}
	public static XmlConfigReader getInstance(){
	             
		if(instance==null){
			Lock( syncRoot) { 
				if(instance==null){
					instance=new XmlConfigReader();
				}
			}
		}
		return instance;
	}
}

对比:

        单例模式分两类,这种静态初始化的方式是在类被加载时实例化,与懒汉式的第一次被引用时才实例化相比提前占用系统资源;但懒汉式需要加锁保证多线程访问的安全性,饿汉式却不需要.我们只好择其善者而用之

 

项目中的单例应用:

         DRP中几乎每个模块都有Manager,在系统开发的初期,因为只有ClientManager,使用单例模式如下:

public class ClientManager {
	private static ClientManager instance=new ClientManager();

	private ClientManager(){}
	
	public static ClientManager getInstance(){
		return instance;
	}
}

         随着系统复杂度的增加,出现越来越多的Manager,ItemManager,FlowCardManager,而且这时候ManagerDao进行了分离,出现了分层.系统采用了抽象工厂+反射技术实现Manager类和Dao类的实例化.单例又被应用在工厂中.

public class BeanFactory {

	private static BeanFactory instance=new BeanFactory();
	
	private final String beansConfigFile="beans-config.xml";
	
	private Document doc;

	private BeanFactory(){
		try {			
			doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
		} catch (DocumentException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	
	public static BeanFactory getInstance(){
		return instance;
	}
}

        以下这段代码是工厂类中得到Manager的单例实现的一部分.开始还真以为是享元模式,后来发现这个实现比享元模式还要灵活.它能保证对象只有一个实例,因此还是单例模式的应用.越到后面用到的东西越多,已经不仅仅局限于某一个模式或技术了,享元,单例,工厂,代理……


//保存Service相关对象
private Map serviceMap=new HashMap();
/**
	 * 根据产品编号取得service系列产品
	 * @param beanId
	 * @return
	 */
	public synchronized Object getServiceObject(Class c){
		//如果存在相关对象实例,返回
		if(serviceMap.containsKey(c.getName())){
			return serviceMap.get(c.getName());
		}
		Element beanElt=(Element)doc.selectSingleNode("//service[@id=\"" + c.getName() +"\"]");
		String className=beanElt.attributeValue("class");
		Object service=null;
		try {
			service=Class.forName(className).newInstance();
			//将创建好的对象放到map中
			serviceMap.put(c.getName(), service);
			
		} catch (Exception e) {
			throw new RuntimeException();
		}
		return service;
	}


        通过以上分析和应用,再看单例模式的重点:

        实现上,私有静态成员变量/私有构造方法/公共的静态方法;解决了全局访问和实例化控制的问题.

       单例的意义不在于创建,而在于访问,也就是说,要访问或调用的对象如果不存在就创建一个,这是唯一一个,之后不能再创建;如果存在就返回该对象,尽管该对象的属性因为被重新赋值改变过无数次,对象是唯一的但不是一成不变的.


Java项目(5)——单例模式的应用与研究