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 , 而且这时候 Manager Dao 进行了分离 , 出现了分层 . 系统采用了抽象工厂 + 反射技术实现 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;
	}


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

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

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


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值