大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
作为对象的创建模式[GOF ] 单例模式确保某一个类只有一个实例 而且自行实例化并向整个系统提供这个实例 这个类称为单例类
成都创新互联是一家专注于成都网站制作、做网站与策划设计,鲁甸网站建设哪家好?成都创新互联做网站,专注于网站建设十年,网设计领域的专业建站公司;建站业务涵盖:鲁甸等地区。鲁甸做网站价格咨询:028-86922220
单例模式的要点
单例单例
显然单例模式的要点有三个 一是某各类只能有一个实例 二是它必须自行创建这个事例 三是它必须自行向整个系统提供这个实例 在下面的对象图中 有一个 单例对象 而 客户甲 客户乙 和 客户丙 是单例对象的三个客户对象 可以看到 所有的客户对象共享一个单例对象 而且从单例对象到自身的连接线可以看出 单例对象持有对自己的引用
资源管理
一些资源管理器常常设计成单例模式
在计算机系统中 需要管理的资源包括软件外部资源 譬如每台计算机可以有若干个打印机 但只能有一个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 提供这样一个方法 由于子类必须允许父类以构造子调用产生实例 因此 它的构造子必须是公开的 这样一来 就等于允许了以这样方式产生实例而不在父类的登记中 这是登记式单例类的一个缺点
lishixinzhi/Article/program/Java/gj/201311/27416
单例模式( )
单例模式是设计模式中使用最为普遍的模式之一 它是一种对象创建模式 用于产生一个对象的具体实例 它可以确保系统中一个类只产生一个实例 在Java语言中 这样的行为能带来两大好处
( )对于频繁使用的对象 可以省略创建对象所花费的时间 这对于那些重量级对象而言 是非常可观的一笔系统开销
( )由于new操作的次数减少 因而对系统内存的使用频率也会降低 这将减轻GC压力 缩短GC停顿时间
因此对于系统的关键组件和被频繁使用的对象 使用单例模式便可以有效地改善系统的性能
单例模式的参与者非常简单 只有单例类和使用者两个 如表 所示
表 单例模式角色
它的基本结构如图 所示
图 单例模式类图
单例模式的核心在于通过一个接口返回唯一的对象实例 一个简单的单例实现如下
public class Singleton {
private Singleton(){
System out println( Singleton is create ) //创建单例的过程可能会比较慢
}
private static Singleton instance = new Singleton()
public static Singleton getInstance() {
return instance;
}
}
注意代码中的重点标注部分 首先单例类必须要有一个private访问级别的构造函数 只有这样 才能确保单例不会在系统中的其他代码内被实例化 这点是相当重要的 其次 instance成员变量和getInstance()方法必须是static的
注意 单例模式是非常常用的一种结构 几乎所有的系统中都可以找到它的身影 因此 希望读者可以通过本节 了解单例模式的几种实现方式及其各自的特点
这种单例的实现方式非常简单 而且十分可靠 它唯一的不足仅是无法对instance实例做延迟加载 假如单例的创建过程很慢 而由于instance成员变量是static定义的 因此在JVM加载单例类时 单例对象就会被建立 如果此时 这个单例类在系统中还扮演其他角色 那么在任何使用这个单例类的地方都会初始化这个单例变量 而不管是否会被用到 比如单例类作为String工厂 用于创建一些字符串(该类既用于创建单例Singleton 又用于创建String对象)
public class Singleton {
private Singleton() {
System out println( Singleton is create )
//创建单例的过程可能会比较慢
}
private static Singleton instance = new Singleton()
public static Singleton getInstance() {
return instance;
}
public static void createString(){ //这是模拟单例类扮演其他角色
System out println( createString in Singleton )
}
}
返回目录 Java程序性能优化 让你的Java程序更快 更稳定
编辑推荐
Java程序设计培训视频教程
J EE高级框架实战培训视频教程
J ME移动开发实战教学视频
Visual C++音频/视频技术开发与实战
Oracle索引技术
lishixinzhi/Article/program/Java/gj/201311/27837
单例模式(Singleton) ,属于最常见的设计模式之一,大部分系统都会用到,目的是为了维护系统中唯一的一个实例。\x0d\x0a可分为eager模式,示例代码如下:\x0d\x0aJava代码\x0d\x0a1.class EagerSingleton{\x0d\x0a2. private static final EagerSingleton m_instance = new EagerSingleton();\x0d\x0a3. private EagerSingleton(){}\x0d\x0a4. public static EagerSingleton getInstance(){\x0d\x0a5. return m_instance;\x0d\x0a6. }\x0d\x0a7.}\x0d\x0aclass EagerSingleton{\x0d\x0aprivate static final EagerSingleton m_instance = new EagerSingleton();\x0d\x0aprivate EagerSingleton(){}\x0d\x0apublic static EagerSingleton getInstance(){\x0d\x0areturn m_instance;\x0d\x0a}\x0d\x0a}\x0d\x0a和 lazy模式,示例代码如下:\x0d\x0aJava代码\x0d\x0a1.class LazySingleton{\x0d\x0a2. private static LazySingleton m_instance = null;\x0d\x0a3. private LazySingleton(){}\x0d\x0a4. public synchronized static getInstance(){\x0d\x0a5. if(m_instance == null){\x0d\x0a6. m_instance = new LazySingleton();\x0d\x0a7. }\x0d\x0a8. return m_instance;\x0d\x0a9. }\x0d\x0a10.}\x0d\x0aclass LazySingleton{\x0d\x0aprivate static LazySingleton m_instance = null;\x0d\x0aprivate LazySingleton(){}\x0d\x0apublic synchronized static getInstance(){\x0d\x0aif(m_instance == null){\x0d\x0am_instance = new LazySingleton();\x0d\x0a}\x0d\x0areturn m_instance;\x0d\x0a}\x0d\x0a}\x0d\x0ajava源码中,Runtime.getRuntime()就是单例的一个例子。\x0d\x0a单例模式的精神就是整个系统中维护一个实例,推广开来,如果在一个系统中需要维护多个示例,那么就产生了多例模式(multiton)。\x0d\x0a多例模式(Multiton) ,通过聚集对象了保留自身的多个示例,根据客户端的参数返回所需要的实例。\x0d\x0a示例代码如下:\x0d\x0aJava代码\x0d\x0a1.class Multiton{\x0d\x0a2. private final int INSTANCE_SIZE = 10;\x0d\x0a3. private static Map instances = new HashMap(INSTANCE_SIZE);\x0d\x0a4. private String name;\x0d\x0a5. private Multiton(){}\x0d\x0a6. private Multiton(String name){\x0d\x0a7. this.name = name;\x0d\x0a8. }\x0d\x0a9. public synchronized static getInstance(String name){\x0d\x0a10. if(instances.containsKey(name)){\x0d\x0a11. return instances.get(name);\x0d\x0a12. }\x0d\x0a13. else{\x0d\x0a14. ins = new Multiton(name);\x0d\x0a15. instances.put(name, ins);\x0d\x0a16. return ins;\x0d\x0a17. }\x0d\x0a18. }\x0d\x0a19.}\x0d\x0aclass Multiton{\x0d\x0aprivate final int INSTANCE_SIZE = 10;\x0d\x0aprivate static Map instances = new HashMap(INSTANCE_SIZE);\x0d\x0aprivate String name;\x0d\x0aprivate Multiton(){}\x0d\x0aprivate Multiton(String name){\x0d\x0athis.name = name;\x0d\x0a}\x0d\x0apublic synchronized static getInstance(String name){\x0d\x0aif(instances.containsKey(name)){\x0d\x0areturn instances.get(name);\x0d\x0a}\x0d\x0aelse{\x0d\x0ains = new Multiton(name);\x0d\x0ainstances.put(name, ins);\x0d\x0areturn ins;\x0d\x0a}\x0d\x0a}\x0d\x0a}\x0d\x0a[nextpage]\x0d\x0a一个实用的例子就是KeyGenerator, 示例代码如下:\x0d\x0aJava代码\x0d\x0a1.class KeyGenerator{\x0d\x0a2. private final int POOL_SIZE = 20;\x0d\x0a3. private static Map instances = new HashMap(16);\x0d\x0a4. private KeyInfo keyinfo;\x0d\x0a5. private KeyGenerator(){}\x0d\x0a6. private KeyGenerator(String keyName){\x0d\x0a7. this.keyinfo = new KeyInfo(POOL_SIZE, keyName);\x0d\x0a8. }\x0d\x0a9. public synchronized static getInstance(String keyName){\x0d\x0a10. if(instances.containsKey(keyName)){\x0d\x0a11. return (KeyGenerator)instances.get(keyName);\x0d\x0a12. }\x0d\x0a13. else{\x0d\x0a14. keyGen = new KeyGenerator(keyName);\x0d\x0a15. instances.put(name, keyGen);\x0d\x0a16. return keyGen;\x0d\x0a17. }\x0d\x0a18. }\x0d\x0a19. public synzhronized int getNextKey(){\x0d\x0a20. return keyinfo.getNextKey();\x0d\x0a21. }\x0d\x0a22. }\x0d\x0aclass KeyGenerator{\x0d\x0aprivate final int POOL_SIZE = 20;\x0d\x0aprivate static Map instances = new HashMap(16);\x0d\x0aprivate KeyInfo keyinfo;\x0d\x0aprivate KeyGenerator(){}\x0d\x0aprivate KeyGenerator(String keyName){\x0d\x0athis.keyinfo = new KeyInfo(POOL_SIZE, keyName);\x0d\x0a}\x0d\x0apublic synchronized static getInstance(String keyName){\x0d\x0aif(instances.containsKey(keyName)){\x0d\x0areturn (KeyGenerator)instances.get(keyName);\x0d\x0a}\x0d\x0aelse{\x0d\x0akeyGen = new KeyGenerator(keyName);\x0d\x0ainstances.put(name, keyGen);\x0d\x0areturn keyGen;\x0d\x0a}\x0d\x0a}\x0d\x0apublic synzhronized int getNextKey(){\x0d\x0areturn keyinfo.getNextKey();\x0d\x0a}\x0d\x0a}