Singleton 模式

学习Singleton模式
单例模式

三个要点:
一.是某各类只能有一个实例
二.是它必须自行创建这个事例
三.是它必须自行向整个系统提供这个实例

如场景
对一些类来说,只有一个实例是很重要的。虽然系统中可以有许多打印机,但却只应该有一个打印机服务程序,只应该有一个文件系统和一个窗口管理器。

一.饿汉式单例类
Java代码
public class EagerSingleton
{
// 在这个类被加载时,静态变量m_instance 会被初始化,此时类的私有构造子会调
//用。这时候,单例类的惟一实例就被创建出来了。
private static final EagerSingleton m_instance = new EagerSingleton();
/**
* 私有的默认构造子
*/
private EagerSingleton() { }
/**
* 静态工厂方法
*/
public static EagerSingleton getInstance()
{
return m_instance;
}
}
  Java 语言中单例类的一个最重要的特点是类的构造子是私有的,从而避免外界利用构造子直接创建出任意多的实例。值得指出的是,由于构造子是私有的,因此,此类不能被继承。


二.懒汉式单例类
Java代码
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;
}
}
1)同样,由于构造子是私有的,因此,此类不能被继承。

2)饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的,在饿汉式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲,这个比懒汉式单例类稍差些。

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


三.登记式单例类
父类源码
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 = "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 需要父类的帮助才能实例化。

下面是子类的源代码。
Java代码
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 可以通过这个方法,返还自已的实例。

而这样做的缺点是
1)由于数据类型不同,无法在RegSingleton 提供这样一个方法。由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样方式产生实例而不在父类的登记中。

2)GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值