单例模式的结构 单例模式有以下的特点:
.. 单例类只可有一个实例。
.. 单例类必须自己创建自己这惟一的实例。
.. 单例类必须给所有其他对象提供这一实例。
虽然单例模式中的单例类被限定只能有一个实例,但是单例模式和单例类可以很容易被推广到任意且有限多个实例的情况,这时候称它为多例模式(Multiton Pattern) 和多例类(Multiton Class),请见"专题:多例(Multiton )模式与多语言支持"一章
由于
Java 语言的特点,使得单例模式在Java 语言的实现上有自己的特点。这些特点主要表现在单例类如何将自己实例化上。
饿汉式单例类饿汉式单例类是在Java 语言里实现得最为简便的单例类,下面所示的类图描述了一个饿汉式单例类的典型实现。
从图中可以看出,此类已经自已将自己实例化。
代码清单1:饿汉式单例类
public class EagerSingleton { private static final EagerSingleton m_instance = new EagerSingleton(); /** * 私有的默认构造子 */ private EagerSingleton() { } /** * 静态工厂方法 */ public static EagerSingleton getInstance() {
·224·Java 与模式 return m_instance; } } |
读者可以看出,在这个类被加载时,静态变量m_instance 会被初始化,此时类的私有构造子会被调用。这时候,单例类的惟一实例就被创建出来了。
Java 语言中单例类的一个最重要的特点是类的构造子是私有的,从而避免外界利用构造子直接创建出任意多的实例。值得指出的是,由于构造子是私有的,因此,此类不能被继承。
懒汉式单例类
与饿汉式单例类相同之处是,类的构造子是私有的。与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时将自己实例化。如果加载器是静态的,那么在懒汉式单例类被加载时不会将自己实例化。如下图所示,类图中给出了一个典型的饿汉式单例类实现。
代码清单2:懒汉式单例类
package com.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 语言,并将它自己实例化的方式从懒汉式改为饿汉式。只是它的子类实例化的方式只能是懒汉式的, 这是无法改变的。如下图所示是登记式单例类的一个例子,图中的关系线表明,此类已将自己实例化。
代码清单3:登记式单例类
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 = "com.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 需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子。图中的关系表明,此类是由父类将子类实例化的。
下面是子类的源代码。
代码清单4:登记式单例类的子类
import java.util.HashMap; public class RegSingletonChild extends RegSingleton { public RegSingletonChild() {} /** * 静态工厂方法 */ static public RegSingletonChild getInstance() { return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" ); } /** * 一个示意性的商业方法 */ public String about() { return "Hello, I am RegSingletonChild."; } } |
在GoF 原始的例子中,并没有getInstance() 方法,这样得到子类必须调用的getInstance(String name)方法并传入子类的名字,因此很不方便。本章在登记式单例类子类的例子里,加入了getInstance() 方法,这样做的好处是RegSingletonChild 可以通过这个方法,返还自已的实例。而这样做的缺点是,由于数据类型不同,无法在RegSingleton 提供这样一个方法。由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样方式产生实例而不在父类的登记中。这是登记式单例类的一个缺点。
GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。这是登记式单例类的另一个缺点。
相关推荐
单例模式单例模式单例模式单例模式单例模式单例模式单例模式单例模式
C#单例模式C#单例模式详解C#单例模式详解C#单例模式详解
单例模式详解~~单例模式详解~~单例模式详解~~
2020-02-10 王争设计模式之美进入课程讲述:冯永吉时长 10:21大小 8.31M上两节课中,我们针对单例模式,讲解了单例的应用场景、几种常见的代码实现
首先向关注过我这个系列...这立刻让我想到了最常用也是最简单最容易理解的一个设计模式 单例模式 何为 单例模式 ? 故名思议 即 让 类 永远都只能有一个实例。 由于 示例代码 比较简单 我也加了注释,这里就不在赘述
单例模式是最简单的设计模式之一,但是对于Java的开发者来说,它却有很多缺陷。在本月的专栏中,David Geary探讨了单例模式以及在面对多线程(multithreading)、类装载器(classloaders)和序列化(serialization)时...
单例模式的七种实现方法以及分析,可以作文大作业提交 1.前言 4 1.1 课题的研究背景 4 1.2 课题主要研究目标 4 2.相关技术简介 4 2.1Java简介 4 2.2IDEA简介 4 3. 单例模式的7种实现方式 5 3.1饿汉式(使用静态常量...
一个简单的java工程,包含注释,一目了然,其中包含了单例模式的所有实现方式,懒汉式,饿汉式,双重校验,枚举,静态内部类等方式实现单例。
单例模式--只能弹出一个窗体 只能弹出一个窗体
设计模式之七种单例模式代码及ppt,包含多线程环境测试和反序列化测试
单例模式和工厂模式结合应用,实现了产品的生产,适合用做课程设计,包含详细文档和代码。Java语言。喜欢的可以下载来看看那
几种单例模式的书写方式
使用单例模式创建学生管理系统(饿汉式、懒汉式)
php单例模式php单例模式php单例模式php单例模式
模式就像是OOP开发人员的配方,每种模式都提供了所需的成分。模式对OOP开发人员尤其有用,因为它有助于创建稳定的API,...本章将介绍两种常用的模式:单例模式和工厂模式。前者被称为类的职责,后者被称为类的多态性。
这个讲的是单例模式的多种不同实现方式,希望对单例感兴趣的同学看看
是http://blog.csdn.net/lxq_xsyu/article/category/1544127博客中java设计模式的源代码。下载前请先看《设计模式——单例模式》一文。
Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式Java SE程序 单例模式...
设计模式C++学习之单例模式(Singleton)
此示例展示了Qml 的单例模式(类似全局对象,只生成一次实例,可全局使用) surfsky.cnblogs.com