您的位置:首页 > 其它

浅学设计模式之单例<singleton>模式 .

2012-12-05 14:37 603 查看
关于单例模式,可能是23种模式里面最容易理解的一种模式了,这篇文章里主要是整理了一下从网上搜集的材料,文字部分大部分直接从网上拷贝而来。中间有部分自己的理解。

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

单例模式适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统,它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统的不同对象访问,因此需要一个全局的访问指针,这便是众所周知的单例模式的应用。当然这只有在你确信你不再需要任何多于一个的实例的情况下。

尽管单例设计模式如在下面的图中的所显示的一样是最简单的设计模式,但对于粗心的Java开发者来说却呈现出许多缺陷。

在《设计模式》一书中,作者这样来叙述单例模式的:确保一个类只有一个实例并提供一个对它的全局访问指针。

下图说明了单例模式的类图。



单例模式的类图

正如你在上图中所看到的,这不是单例模式的完整部分。此图中单例类保持了一个对唯一的单例实例的静态引用,并且会从静态getInstance()方法中返回对那个实例的引用。

很多人都会写的一种单例类型:

[java]
view plaincopyprint?

public class Singleton {
private static Singleton <SPAN style="FONT-SIZE: 16px">INSTANCE</SPAN> = null;
private Singleton(){

}
public static Singleton getInstance(){
if(singleton == null){
<SPAN style="FONT-SIZE: 16px">INSTANCE</SPAN> = new Singleton();
}
return <SPAN style="FONT-SIZE: 16px">INSTANCE</SPAN>;
}

}

public class Singleton {
private static Singleton INSTANCE = null;
private Singleton(){

}
public static Singleton getInstance(){
if(singleton == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}

}


但是这种单例类型在多线程中是不安全。有可能会出现两个INSTANCE.为什么呢?

如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。

懒汉式单例模式:

[java]
view plaincopyprint?

public class Singleton {
private static Singleton INSTANCE = null;

// Private constructor suppresses

// default public constructor

private Singleton() {}

//thread safe and performance promote

public static Singleton getInstance() {
if(INSTANCE == null){
synchronized(Singleton.class){
//if 2 or more thread go into first null check at same time , it will be instance more then once.so we must check it again.

if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}

public class Singleton {
private static Singleton INSTANCE = null;

// Private constructor suppresses
// default public constructor
private Singleton() {}

//thread safe and performance  promote
public static  Singleton getInstance() {
if(INSTANCE == null){
synchronized(Singleton.class){
//if 2 or more thread go  into first null check at same time , it will be instance more then once.so we must check it again.
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}


还有另外一个方法(也被称为饿汉式单例模式):

[java]
view plaincopyprint?

public class Singleton {
private final static Singleton INSTANCE = new Singleton();

// Private constructor suppresses

private Singleton() {}

// default public constructor

public static Singleton getInstance() {
return INSTANCE;
}
}

public class Singleton {
private final static Singleton INSTANCE = new Singleton();

// Private constructor suppresses
private Singleton() {}

// default public constructor
public static Singleton getInstance() {
return INSTANCE;
}
}


这样写就会避免出现两个INSTANCE了。

比较:

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。
懒汉式适合单线程,多线程情况下如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。
从实现方式来讲他们最大的区别就是懒汉式是延时加载,

他是在需要的时候才创建对象,而饿汉式在加载类时创建实例。

饿汉式无需关注多线程问题、写法简单明了、能用则用。但是它是加载类时创建实例(上面有个朋友写错了)、所以如果是一个工厂模式、缓存了很多实例、那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。
懒汉式的优点是延时加载、缺点是应该用同步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: