场景
对象只要利用自己的属性完成了自己的任务.那该对象就是承担了责任。
除了维持了自身的一致性,该对象无需承担其他任何责任。
如果该对象还承担着其他责任,而其他对象又依赖于该特定对象所承担的贵任,我们就需要得到该特定对象。
就像我和我的女朋友去超市购物使用的购物车一样。
意图
将类的责任集中到唯一的单体对象中,确保该类只有一个实例.
并且为该类提供一个全局访间点。
难点
不在于单体模式的实现,而在于在系统中任何识别单体和保证单体的唯一性。
应用场景
1,提供唯一的私有构造器,避免多个单体(Singleton)对象被创建,这也
意味着该单体类不能有子类,那声明你的单例类为final是一个好主意,这样意图明确,并且让编译器去使用一些性能优化选项。
如果有子类的话使用protected, protected的构造方法可以被其子类以及在同一个包中的其它类调用。
私有构造器可以防止客户程序员通过除由我们提供的方法之外的任意方式来创建一个实例。
2,使用静态域( static final)来维护实例。
将单体对象作为单体类的一个静态域实例化。
使用保存唯一实例的static变量,其类型就是单例类型本身。
需要的话使用final,使其不能够被重载. 例如:
private static Rutime corcentRuntime = new Runtime();
3、使用静态方法(static Method)来监视实例的创建。
(1)加载时实例化(饿汉式)
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
(2)使用时实例化(懒汉式)
public class Singleton {
/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton instance = null;
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/*加上synchronized,但是每次调用实例时都会加载**/
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
4,单体对象的成员变量(属性):即单体对象的状态 通过单例对象的初始化来实现成员变量的初始化。 通过方法对单体对象的成员变量进行更新操作。
public class Singleton {
private static final Singleton Singleton_instance=null;
private Vector properties = null;
protected Singleton() {
//使用运行时收集到的需要的信息,进行属性的初始化等操作。
}
private static synchronized void syncInit() {
if (Singleton _instance == null){
Singleton _instance = new Singleton();
}
}
public static Singleton getInstance() {
if (Singleton _instance == null){
syncInit();
}
return Singleton _instance;
}
public synchronized void updateProperties() {
// 更新属性的操作。
}
public Vector getProperties() {
return properties;
}
}
单例模式的一般方法
单体摸式主要作用是保证在Java应用程序中,一个Class只有一个实例存
在。
一般有三种方法,下面我就具体来说说这三种方法.
1、定义一个类,它的构造函数为private的,所有方法为static的。
如java lang. Math其他类对它的引用全部是通过类名直接引用。
public final class Math {
/**
* Don't let anyone instantiate this class.
*/
private Math() {}
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
public static double sin(double a) {
return StrictMath.sin(a);
// default impl. delegates to StrictMath
}
2、定义一个类,它的构造函数为private的,它有一个static的private的该类变量,
在类初始化时实例化,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
3.定义一个类,它的构造函数为private的.它有一个.static的private的boolean变
量,用于表示是否有实例存在。
public class PrintSpooler {
static boolean instance_flag = false; //true if 1 instance
public PrintSpooler() throws SingletonException {
if (instance_flag)
throw new SingletonException("Only one spooler allowed");
else
instance_flag = true; //set flag for 1 instance
System.out.println("spooler opened");
}
public void finalize() {
instance_flag = false; //clear if destroyed
}
}
单例模式的表现形式
第一种形式:懒汉式,也是常用的形式。
public class SingletonClass{
private static SingletonClass instance=null;
public static synchronized SingletonClass getInstance()
{
if(instance==null)
{
instance=new SingletonClass();
}
return instance;
}
private SingletonClass(){
}
}
第二种形式:饿汉式
/**对第一行static的一些解释
java允许我们在一个类里面定义静态类。比如内部类(nested class)。
把nested class封闭起来的类叫外部类。
在java中,我们不能用static修饰顶级类(top level class)。
只有内部类可以为static。
**/
public class Singleton{
//在自己内部定义自己的一个实例,只供内部调用
private static final Singleton instance = new Singleton();
private Singleton(){
//do something
}
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance(){
return instance;
}
}
第三种形式: 双重锁的形式。
public class Singleton{
private static Singleton instance=null;
private Singleton(){
//do something
}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(null==instance){
instance=new Singleton();
}
}
}
return instance;
}
}
优点
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。