单例模式是很新颖的1个模式,很少有人拿它跟其他模式相比,由于,单例模式很简单,很特别,作用就是保证1个类有唯逐一个实例,并让1个全局变量使得它能被访问.而保证这个类只被实例化1次的办法就是把构造函数变成私有的,除它自己都不能new新对象,然后把实例化的进程写在类本身的公有方法里,是不是new新对象只有它自己判断决定,已有了1个实例就直接返回已存在的对象,没有就new1个新实例.其他类想实例化1个对象时调这个公有方法.
//饿汉式
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"即"两重锁定"的概念,这是由于还有1种加锁方式,即便用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;
}
}
对照:
单例模式分两类,这类静态初始化的方式是在类被加载时实例化,与懒汉式的第1次被援用时才实例化相比提早占用系统资源;但懒汉式需要加锁保证多线程访问的安全性,饿汉式却不需要.我们只好择其善者而用之…
项目中的单例利用:
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的单例实现的1部份.开始还真以为是享元模式,后来发现这个实现比享元模式还要灵活.它能保证对象只有1个实例,因此还是单例模式的利用.越到后面用到的东西越多,已不单单局限于某1个模式或技术了,享元,单例,工厂,代理……
//保存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;
}
通过以上分析和利用,再看单例模式的重点:
实现上,私有静态成员变量/私有构造方法/公共的静态方法;解决了全局访问和实例化控制的问题.
单例的意义不在于创建,而在于访问,也就是说,要访问或调用的对象如果不存在就创建1个,这是唯逐一个,以后不能再创建;如果存在就返回该对象,虽然该对象的属性由于被重新赋值改变过无数次,对象是唯1的但不是1成不变的.