• 单例模式(Singleton)


    4.3 单例模式(Design Pattern:Singleton)

    单例模式属于创建型模式,目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。考虑这样一种对象,这个对象应该在程序启动时被创建,并且在结束时被删除,如应用程序的基础高层对象。通过这个对象可以得到系统中其他的对象,这些基础对象可能是前面提到的工厂对象(Factories),用来创建其他对象;也可能是管理器对象(managers),负责控管其他对象;或者是全局注册表(Registry)。类似这种类型的对象不该被创造出多份。
    4.3.1  单例模式的实现
    下面给出单例模式的实现。单例模式参与者如图4.8所示。其中Singleton定义了一个getInstance操作,允许客户访问它的惟一实例。可能负责创建它的惟一实例。
    图4.8  经典单例模式类图

    如图4.8和代码4.33,可以看到,经典单例模式的实现非常简单。而正是由于概念和实现上的简单,没有顾及到逻辑概念上、测试性、全局依赖、类装载器、序列化、线程安全以及不同JVM之间等等方面的问题,造成了很多的误用。
    代码4.33  Singleton.java
    package chapter4.pattern.singleton;
    public class Singleton {
      private static Singleton instance;
      /**
       * 不允许通过构造字来实例化
       */
      private Singleton() {
      }
      /**
       * 使用synchronized关键字,保障Singleton的线程安全
       */
      public synchronized static Singleton getInstance() {
        if (instance == null) {
          instance = new Singleton();
        }
        return instance;
      }
    }
    注意:Singleton模式应当谨慎使用。代码4.33中给出了一种合理的使用方法,通过将Singleton的构造子声明为私有,杜绝了外部或者子类的实例化倾向(当然这也是允许的)。
    通过为getInstance()方法签署synchronized锁,保障了Singleton是线程安全的。此处所指的线程不安全是指在多线程环境下,可能产生不同Singleton实例。另外,getInstance()方法实际上是一种静态工厂方法,这是工厂模式的一个变种。考虑上节中工厂模式的例子,尝试结合Factory和Singleton,如代码4.34所示。
    代码4.34  UtilServiceSingletonFactory.java
    package chapter4.pattern.singleton;
    import chapter4.pattern.factory.dipioc.ConcreteUtil;
    import chapter4.pattern.factory.dipioc.UtilService;
    public class UtilServiceSingletonFactory {
      private static UtilServiceSingletonFactory instance;
      /**
       * 允许子类实例化
       */
      protected UtilServiceSingletonFactory() {
      }
      public synchronized static UtilServiceSingletonFactory getInstance() {
        if (instance == null) {
          instance = new UtilServiceSingletonFactory();
        }
        return instance;
      }
      public UtilService make() {
        return new ConcreteUtil();
      }
    }
    客户代码可以是这样:
    UtilService utilService = UtilServiceSingletonFactory.getInstance().make();
    可以看到,通过单例工厂使得工厂对象实例数不超过1个,同时给出了Factory Method的实现(make方法),通过变换构造子修饰(private->protected),保留了Factory的派生性。如果不考虑派生性,完全有理由使用静态工厂而不是单例工厂,静态工厂使工厂类不需要被实例化,客户代码可以是这样:
    UtilService utilService = UtilServiceSingletonFactory.make();

    4.3.2  单例注册表
    接下来将要介绍Singleton模式的另一种常用实现,即单例注册表(Singleton Registry),如代码4.35~4.39所示。
    代码4.35  FactorySingletonRegistryUsage.java
    package chapter4.pattern.singleton;
    public class FactorySingletonRegistryUsage {
      public static void main(String[] args) {
        //实例化工厂注册表
        FactorySingletonRegistry registry = FactorySingletonRegistry.getInstance();
        //<- 通过反射机制,使得注册表可以依据给定的工厂全限定名返回具体工厂实例
        //第一次索取
        BeanFactory xmlBeanFactory1 = registry.getBeanFactory("chapter4.pattern.singleton.XmlBeanFactory");
        BeanFactory listableBeanFactory1 = registry.getBeanFactory("chapter4.pattern.singleton.ListableBeanFactory");
        //第二次索取
        BeanFactory xmlBeanFactory2 = registry.getBeanFactory("chapter4.pattern.singleton.XmlBeanFactory");
        BeanFactory listableBeanFactory2 = registry.getBeanFactory("chapter4.pattern.singleton.ListableBeanFactory");
        //->
        //比较先后两次索取的工厂实例,希望得到同一实例的工厂引用,结果正确
        System.out.println(xmlBeanFactory1.hashCode() == xmlBeanFactory2.hashCode());
        System.out.println(listableBeanFactory1.hashCode() == listableBeanFactory2.hashCode());
    }
    }
    代码4.36  FactorySingletonRegistry.java
    import java.util.HashMap;
    import java.util.Map;
    public class FactorySingletonRegistry {
      private static FactorySingletonRegistry instance;
      private static Map factoryMap = new HashMap();①
      private FactorySingletonRegistry() {
      }
      public synchronized static FactorySingletonRegistry getInstance() {
        if (instance == null) {
          instance = new FactorySingletonRegistry();
        }
        return instance;
      }

      public synchronized BeanFactory getBeanFactory(String factoryClassName) {②
        BeanFactory factory = (BeanFactory)factoryMap.get(factoryClassName);
        if (factory != null) return factory;
        try {
         factory = (BeanFactory)Class.forName(factoryClassName).newInstance();③
        } catch (ClassNotFoundException e) {
          System.out.println("Couldn't find class " + factoryClassName);
        } catch (InstantiationException e) {
          System.out.println("Couldn't instantiate an object of type " + factoryClassName);
        } catch (IllegalAccessException e) {
          System.out.println("Couldn't access class " + factoryClassName);
        }
        factoryMap.put(factoryClassName, factory);
        return factory;
      }
    }
    代码4.37  BeanFactory.java
    public interface BeanFactory {
    }
    代码4.38  ListableBeanFactory.java
    public class ListableBeanFactory implements BeanFactory {
      public ListableBeanFactory() {
        System.out.println("ListableBeanFactory Created");
      }
    }
    代码4.39  XmlBeanFactory.java
    public class XmlBeanFactory implements BeanFactory {
      public XmlBeanFactory() {
        System.out.println("XmlBeanFactory Created");
      }
    }
    对单例注册表的简单运作方式,做如下说明:
    (1)请看代码4.36,首先这个类是一个单例类,在①处使用了Map对象,这是一个类,持有聚集的讯息。所谓聚集通常就是在Map中以名值对(field-value)的形式存储一系列各类对象的实例引用,通过put(field,value)存储,通过get(field)取得value。在代码4.36的getBeanFactory方法中,通过对factoryMap的存取,可以使该单例注册表持有任意数量的工厂实例,并且通过if (factory != null)的判断,保证了返回的是对同一个工厂实例的引用。
    (2)注意代码4.36中的②处,getBeanFactory(String factoryClassName)是一个参数化的工厂方法,和在代码4.26中的类似。
    说明:如果工厂方法依赖一个参数标识来决定产品的具体生产行为,那么可以说这就是一个参数化工厂方法。参数化工厂的好处是,创建同一产品族系(拥有同一接口的具体产品)时,不再需要衍生具体的工厂子类来对应。主要缺点是工厂职责过于集中,另外一个缺点仍然是所有传统工厂模式的通病,就是由于硬编码的关系,需要使用if/else语句来决定生产方式,无法摆脱Product = new ConcreteProduct()这种代码带来的强依赖性,同时限制了工厂创建产品的种类数目。这也意味着每当引入新的产品时,就需要重新变更关联代码。
    (3)在代码4.36中引入了反射(Reflection)技术,如③所示。在代码4.35中,可以以类的全限定名作为参数传入工厂方法,工厂方法会通过反射技术来实例化那个类,而不需要预先在工厂方法中记载有限的产品集合了。
    至此,给出了单例模式的基本用法,单例模式是一种常用的模式,但也很容易被误用。最后还提到了反射和工厂方法模式的一些结合,这是非常有用的技术。

    转自:http://book.csdn.net/bookfiles/92/100922653.shtml

  • 相关阅读:
    Json对象与Json字符串互转(4种转换方式)
    Web.config配置文件详解
    jQuery BlockUI Plugin Demo 6(Options)
    jQuery BlockUI Plugin Demo 5(Simple Modal Dialog Example)
    jQuery BlockUI Plugin Demo 4(Element Blocking Examples)
    jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
    jQuery BlockUI Plugin Demo 2
    <configSections> 位置引起的错误
    关于jQuery的cookies插件2.2.0版设置过期时间的说明
    jQuery插件—获取URL参数
  • 原文地址:https://www.cnblogs.com/kelin1314/p/1369891.html
Copyright © 2020-2023  润新知