知识大全 Java模式设计之单例模式(一)

Posted

篇首语:孙竹新添绿玉枝,稚禽学习绕檐飞。动中会取归根意,雨过白云横翠微。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java模式设计之单例模式(一)相关的知识,希望对你有一定的参考价值。

Java模式设计之单例模式(一)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  作为对象的创建模式[GOF ] 单例模式确保某一个类只有一个实例 而且自行实例化并向整个系统提供这个实例 这个类称为单例类

  单例模式的要点

  单例单例

  显然单例模式的要点有三个 一是某各类只能有一个实例 二是它必须自行创建这个事例 三是它必须自行向整个系统提供这个实例 在下面的对象图中 有一个 单例对象 而 客户甲 客户乙 和 客户丙 是单例对象的三个客户对象 可以看到 所有的客户对象共享一个单例对象 而且从单例对象到自身的连接线可以看出 单例对象持有对自己的引用

  

  资源管理

  一些资源管理器常常设计成单例模式

  在计算机系统中 需要管理的资源包括软件外部资源 譬如每台计算机可以有若干个打印机 但只能有一个Printer Spooler 以避免两个打印作业同时输出到打印机中 每台计算机可以有若干传真卡 但是只应该有一个软件负责管理传真卡 以避免出现两份传真作业同时传到传真卡中的情况 每台计算机可以有若干通信端口 系统应当集中管理这些通信端口 以避免一个通信端口同时被两个请求同时调用

  需要管理的资源包括软件内部资源 譬如 大多数的软件都有一个(甚至多个)属性(properties)文件存放系统配置 这样的系统应当由一个对象来管理一个属性文件

  需要管理的软件内部资源也包括譬如负责记录网站来访人数的部件 记录软件系统内部事件 出错信息的部件 或是对系统的表现进行检查的部件等 这些部件都必须集中管理 不可政出多头

  这些资源管理器构件必须只有一个实例 这是其一 它们必须自行初始化 这是其二 允许整个系统访问自己这是其三 因此 它们都满足单例模式的条件 是单例模式的应用

  一个例子 Windows 回收站

  Windows x 以后的视窗系统中都有一个回收站 下图就显示了Windows 的回收站

  

  在整个视窗系统中 回收站只能有一个实例 整个系统都使用这个惟一的实例 而且回收站自行提供自己的实例 因此 回收站是单例模式的应用

  双重检查成例

  在本章最后的附录里研究了双重检查成例 双重检查成例与单例模式并无直接的关系 但是由于很多C 语言设计师在单例模式里面使用双重检查成例 所以这一做法也被很多Java 设计师所模仿 因此 本书在附录里提醒读者 双重检查成例在Java 语言里并不能成立 详情请见本章的附录

  单例模式的结构

  单例模式有以下的特点

  …… 单例类只可有一个实例

  …… 单例类必须自己创建自己这惟一的实例

  …… 单例类必须给所有其他对象提供这一实例

  虽然单例模式中的单例类被限定只能有一个实例 但是单例模式和单例类可以很容易被推广到任意且有限多个实例的情况 这时候称它为多例模式(Multiton Pattern) 和多例类(Multiton Class) 请见 专题 多例(Multiton )模式与多语言支持 一章 单例类的简略类图如下所示

  由于Java 语言的特点 使得单例模式在Java 语言的实现上有自己的特点 这些特点主要表现在单例类如何将自己实例化上

  饿汉式单例类饿汉式单例类是在Java 语言里实现得最为简便的单例类 下面所示的类图描述了一个饿汉式单例类的典型实现

  从图中可以看出 此类已经自已将自己实例化

  代码清单 饿汉式单例类

  public class EagerSingleton private static final EagerSingleton m_instance = new EagerSingleton() /** * 私有的默认构造子*/ private EagerSingleton() /** * 静态工厂方法*/ public static EagerSingleton getInstance()

  

   Java 与模式return m_instance

  读者可以看出 在这个类被加载时 静态变量m_instance 会被初始化 此时类的私有构造子会被调用 这时候 单例类的惟一实例就被创建出来了

  Java 语言中单例类的一个最重要的特点是类的构造子是私有的 从而避免外界利用构造子直接创建出任意多的实例 值得指出的是 由于构造子是私有的 因此 此类不能被继承

  懒汉式单例类

  与饿汉式单例类相同之处是 类的构造子是私有的 与饿汉式单例类不同的是 懒汉式单例类在第一次被引用时将自己实例化 如果加载器是静态的 那么在懒汉式单例类被加载时不会将自己实例化 如下图所示 类图中给出了一个典型的饿汉式单例类实现

  

  代码清单 懒汉式单例类

  package javapatterns singleton demos public class LazySingleton private static LazySingleton m_instance = null /** * 私有的默认构造子 保证外界无法直接实例化*/ private LazySingleton() /** * 静态工厂方法 返还此类的惟一实例*/ synchronized public static LazySingleton getInstance()

   if (m_instance == null)

   m_instance = new LazySingleton() return m_instance

  读者可能会注意到 在上面给出懒汉式单例类实现里对静态工厂方法使用了同步化 以处理多线程环境 有些设计师在这里建议使用所谓的 双重检查成例 必须指出的是 双重检查成例 不可以在Java 语言中使用 不十分熟悉的读者 可以看看后面给出的小节

  同样 由于构造子是私有的 因此 此类不能被继承 饿汉式单例类在自己被加载时就将自己实例化 即便加载器是静态的 在饿汉式单例类被加载时仍会将自己实例化 单从资源利用效率角度来讲 这个比懒汉式单例类稍差些

  从速度和反应时间角度来讲 则比懒汉式单例类稍好些 然而 懒汉式单例类在实例化时 必须处理好在多个线程同时首次引用此类时的访问限制问题 特别是当单例类作为资源控制器 在实例化时必然涉及资源初始化 而资源初始化很有可能耗费时间 这意味着出现多线程同时首次引用此类的机率变得较大

  饿汉式单例类可以在Java 语言内实现 但不易在C++ 内实现 因为静态初始化在C++ 里没有固定的顺序 因而静态的m_instance 变量的初始化与类的加载顺序没有保证 可能会出问题 这就是为什么GoF 在提出单例类的概念时 举的例子是懒汉式的 他们的书影响之大 以致Java 语言中单例类的例子也大多是懒汉式的 实际上 本书认为饿汉式单例类更符合Java 语言本身的特点

  登记式单例类

  登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的 本书把他们的例子翻译为Java 语言 并将它自己实例化的方式从懒汉式改为饿汉式 只是它的子类实例化的方式只能是懒汉式的 这是无法改变的 如下图所示是登记式单例类的一个例子 图中的关系线表明 此类已将自己实例化

  

  代码清单 登记式单例类

  import java util HashMap public class RegSingleton static private HashMap m_registry = new HashMap() static RegSingleton x = new RegSingleton() m_registry put( x getClass() getName() x) /** * 保护的默认构造子*/ protected RegSingleton() /** * 静态工厂方法 返还此类惟一的实例*/ static public RegSingleton getInstance(String name)

   if (name == null)

   name = javapatterns singleton demos RegSingleton if (m_registry get(name) == null)

   try m_registry put( name Class forName(name) newInstance() ) catch(Exception e)

   System out println( Error happened ) return (RegSingleton) (m_registry get(name) ) /** * 一个示意性的商业方法*/ public String about()

   return Hello I am RegSingleton 它的子类RegSingletonChild 需要父类的帮助才能实例化 下图所示是登记式单例类子类的一个例子 图中的关系表明 此类是由父类将子类实例化的

  

  下面是子类的源代码

  代码清单 登记式单例类的子类

  import java util HashMap public class RegSingletonChild extends RegSingleton public RegSingletonChild() /** * 静态工厂方法*/ static public RegSingletonChild getInstance()

   return (RegSingletonChild)

  RegSingleton getInstance( javapatterns singleton demos RegSingletonChild ) /** * 一个示意性的商业方法*/ public String about()

   return Hello I am RegSingletonChild

  在GoF 原始的例子中 并没有getInstance() 方法 这样得到子类必须调用的getInstance(String name)方法并传入子类的名字 因此很不方便 本章在登记式单例类子类的例子里 加入了getInstance() 方法 这样做的好处是RegSingletonChild 可以通过这个方法 返还自已的实例 而这样做的缺点是 由于数据类型不同 无法在RegSingleton 提供这样一个方法 由于子类必须允许父类以构造子调用产生实例 因此 它的构造子必须是公开的 这样一来 就等于允许了以这样方式产生实例而不在父类的登记中 这是登记式单例类的一个缺点

cha138/Article/program/Java/gj/201311/27416

相关参考

知识大全 java之单例设计模式

  设计模式解决某一类问题最行之有效的方法(java中有种通用设计模式)  单例设计模式解决一个类在内存中只存在一个对象  单例设计模式有两种方式  )饿汉式  先初始化对象当类一进内存就创建好对象 

知识大全 Java与模式之单例模式

Java与模式之单例模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  单例模式(Singlet

知识大全 php设计模式之单例、多例设计模式的应用分析

本篇文章是对php设计模式中的单例与多例设计模式的应用进行了详细的分析介绍需要的朋友参考下   单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量如

知识大全 23种设计模式的Java版--Singleton(单例)

23种设计模式的Java版--Singleton(单例)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 Java单例模式实现

Java单例模式实现  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  单例模式  Q:什么是单例模

知识大全 Java单例模式示例

Java单例模式示例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  概念  Java中单例模式是

知识大全 Java程序性能优化-单例模式(1)

Java程序性能优化-单例模式(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!   

知识大全 Java程序性能优化-单例模式(2)

Java程序性能优化-单例模式(2)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!   

知识大全 Java程序性能优化-单例模式(3)

Java程序性能优化-单例模式(3)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!   

知识大全 Java中单例模式的几种正确实现方法

Java中单例模式的几种正确实现方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  第一种同步