`
步行者
  • 浏览: 167717 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

为什么需要Singleton

阅读更多

为什么需要 单例设计模式(Singleton)?

像下面的一个单例

 

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static synchronized Singleton getInstance(){
		if(instance == null)
			instance = new Singleton();
		return instance;
	}
	public void doSomething(){
		//do something
	}
}


它要实现的主要目标,就是在一个应用中只维护一个Singleton实例

但一个类在一个应用中也是唯一的,为什么不能直接以类作为单例呢?

 

public final class AnotherSingleton{
	private AnotherSingleton(){}
	public static synchronized void doSomething(){
		//do something
	}
}

 

把类的所有方法都改为静态方法,

所有属性都改为静态属性(我们可以把

静态属性看成类的内部状态),

但是不允许实例化,

对类的操作相当于对单例的操作

而且类也可以维护内部状态(通过静态私有属性)

这完全满足了单例的要求。

不知道为什么需要单例模式。。。


因为我想不出来在什么情况下 单例可以满足需求

而 类 不能。

 

 

 

分享到:
评论
66 楼 步行者 2009-06-08  
hoorace 写道
你这个只是一个简单的例子而已,如果在复杂的配置中,调用了N多的api,有的api不是static式的,不能写在static的方法中,这样,为了保证内存中的类只有一份,就需要singleton了!


api不是static的 ,就不能static方法里调用这个api吗?
不是吧。。
65 楼 步行者 2009-06-08  
moonranger 写道
Testability...


why not。。
64 楼 hoorace 2009-06-08  
你这个只是一个简单的例子而已,如果在复杂的配置中,调用了N多的api,有的api不是static式的,不能写在static的方法中,这样,为了保证内存中的类只有一份,就需要singleton了!
63 楼 moonranger 2009-06-08  
Testability...
62 楼 步行者 2009-06-08  
<div class="quote_title">scvptz 写道</div>
<div class="quote_div">
<div class="quote_title">步行者 写道</div>
<div class="quote_div">
<p><span style="font-size: 13px;">因为我想不出来在什么情况下 单例可以满足需求</span></p>
<p><span style="font-size: small;">而 类 不能。</span></p>
</div>
<p>你的追求仅仅只满足于实现需求吗?</p>
<p>如果静态方法在多处被调用,将来某个时候,你希望它不是单例了,那么修改的代码量就非常大了。</p>
<p>如果把单例模式和工厂模式结合起来用,这个时候,需要修改的只是工厂内部的实现,调用单例的地方都不用修改。</p>
<p>更进一步,使用spring来注入,那么连工厂方法也不用写,只需要改一下配置,就可以灵活的在单例和实例之间切换了。</p>
<p> </p>
</div>
<p> </p>
<p>你说的都是针对对象得特性,类当然不能满足</p>
<p><br>类就是全局唯一的,又可以通过静态属性维护内部状态,他是天然的Singleton,但它不是对象,</p>
<p>至于跟工厂模式得结合 ,我觉得不会出现问题,你只需要把工厂类构造成Singleton就行了</p>
<p> </p>
61 楼 scvptz 2009-06-08  
<div class="quote_title">步行者 写道</div>
<div class="quote_div">
<p><span style="font-size: 13px;">因为我想不出来在什么情况下 单例可以满足需求</span></p>
<p><span style="font-size: small;">而 类 不能。</span></p>
</div>
<p>你的追求仅仅只满足于实现需求吗?</p>
<p>如果静态方法在多处被调用,将来某个时候,你希望它不是单例了,那么修改的代码量就非常大了。</p>
<p>如果把单例模式和工厂模式结合起来用,这个时候,需要修改的只是工厂内部的实现,调用单例的地方都不用修改。</p>
<p>更进一步,使用spring来注入,那么连工厂方法也不用写,只需要改一下配置,就可以灵活的在单例和实例之间切换了。</p>
<p> </p>
60 楼 kaka11 2009-06-08  
Singleton如果序列化的话,还要注意序列化问题:
/**
 * @author   kakachen
 */
public class SingletonSer implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -892694328982110567L;

	public static final SingletonSer INSTANCE = new SingletonSer();
	
	private SingletonSer() {

	}

	private Object readResolve() throws ObjectStreamException {
		return INSTANCE;
	}
}

这在<<effective java>>中都有讲到,不过该书的第2版中还讲了如果依赖于这种方法遇到了一些带有引用类型的实例变量必须把它置成transient,不然就有可能被攻击,具体的可以看该书第77条.所以如果是jdk1.5以上优先使用enum来作为序列化的Singleton.
59 楼 步行者 2009-06-08  
kaka11 写道
至于Singleton的同步问题DCL好象是有问题的,所以我推荐使用Bob Lee的Lazy写法:
public class NewSingleton {
	private static class SingletonHolder {
		static NewSingleton INSTANCE = new NewSingleton();
	}

	public static NewSingleton getInstance() {
		return SingletonHolder.INSTANCE;
	}
}


应该加一个 private 构造器
58 楼 kaka11 2009-06-08  
至于Singleton的同步问题DCL好象是有问题的,所以我推荐使用Bob Lee的Lazy写法:
public class NewSingleton {
	private static class SingletonHolder {
		static NewSingleton INSTANCE = new NewSingleton();
	}

	public static NewSingleton getInstance() {
		return SingletonHolder.INSTANCE;
	}
}
57 楼 kaka11 2009-06-08  
步行者 写道
redhat 写道
另外,一般StringUtils是abstract final的,否则不能保证是单例,我可以直接new 一个出来(这是一个漏洞),参见spring的StringUtils。

还有
abstract final 使不能通过编译的。

对于工具类限制有两种方法:
1.加abstract.
2.使构造函数变成private.
个人更推荐第二种方式.
56 楼 步行者 2009-06-08  
redhat 写道
另外,一般StringUtils是abstract final的,否则不能保证是单例,我可以直接new 一个出来(这是一个漏洞),参见spring的StringUtils。

还有
abstract final 使不能通过编译的。
55 楼 zhaomingzm_23 2009-06-08  
步行者 写道
zhaomingzm_23 写道
楼主要注意多线程的问题
还有synchronized修饰的方法最好改成
用锁(ReentrantLock)的双判断模式效果会更好
package singleton;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Singleton {

	/** unique instance */
	private static Singleton sInstance = null;

     /** static lock */
	private static Lock lock = new ReentrantLock();
	
    /** 
	 * Private constuctor
	 */
	private Singleton() {
		super();
	}

	/** 
	 * Get the unique instance of this class.
	 */
	public static Singleton getUniqueInstance() {
		
		if (sInstance == null) {
			lock.lock(); //lock need times.
			try{
				if(sInstance == null){
					sInstance = new Singleton();
				}
			}finally{
				lock.unlock();
			}
		}

		return sInstance;

	}
//.. other code.
}


你好 多线程问题很重要
为什么synchronized修饰的方法改成
用锁(ReentrantLock)的双判断模式效果会更好?
synchronized 会引起线程不同步 或 效率问题吗




这个问题就是效率问题了,你可以参考下jdk1.5 中ConcurrentHashMap 的文档注释,说的很详细。
54 楼 步行者 2009-06-08  
redhat 写道
首先要看看你的类是否需要其他oo特性,简单来说,一些工具类,如StringUtils等,不需要太多继承,也不需要其他继承等,那么就没有必要,就看你的是否需要。

另外,一般StringUtils是abstract final的,否则不能保证是单例,我可以直接new 一个出来(这是一个漏洞),参见spring的StringUtils。


AnotherSingleton 构造函数是 private 的,不能new出来
StringUtils 和 我这个类 有区别
StringUtils 没有内部状态,它就是把管局String的工具函数打包了
而 AnotherSingleton 是有内部状态的(私有静态属性)。
53 楼 步行者 2009-06-08  
zhaomingzm_23 写道
楼主要注意多线程的问题
还有synchronized修饰的方法最好改成
用锁(ReentrantLock)的双判断模式效果会更好
package singleton;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Singleton {

	/** unique instance */
	private static Singleton sInstance = null;

     /** static lock */
	private static Lock lock = new ReentrantLock();
	
    /** 
	 * Private constuctor
	 */
	private Singleton() {
		super();
	}

	/** 
	 * Get the unique instance of this class.
	 */
	public static Singleton getUniqueInstance() {
		
		if (sInstance == null) {
			lock.lock(); //lock need times.
			try{
				if(sInstance == null){
					sInstance = new Singleton();
				}
			}finally{
				lock.unlock();
			}
		}

		return sInstance;

	}
//.. other code.
}


你好 多线程问题很重要
为什么synchronized修饰的方法改成
用锁(ReentrantLock)的双判断模式效果会更好?
synchronized 会引起线程不同步 或 效率问题吗


52 楼 redhat 2009-06-08  
首先要看看你的类是否需要其他oo特性,简单来说,一些工具类,如StringUtils等,不需要太多继承,也不需要其他继承等,那么就没有必要,就看你的是否需要。

另外,一般StringUtils是abstract final的,否则不能保证是单例,我可以直接new 一个出来(这是一个漏洞),参见spring的StringUtils。
51 楼 zhaomingzm_23 2009-06-08  
楼主要注意多线程的问题
还有synchronized修饰的方法最好改成
用锁(ReentrantLock)的双判断模式效果会更好
package singleton;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Singleton {

	/** unique instance */
	private static Singleton sInstance = null;

     /** static lock */
	private static Lock lock = new ReentrantLock();
	
    /** 
	 * Private constuctor
	 */
	private Singleton() {
		super();
	}

	/** 
	 * Get the unique instance of this class.
	 */
	public static Singleton getUniqueInstance() {
		
		if (sInstance == null) {
			lock.lock(); //lock need times.
			try{
				if(sInstance == null){
					sInstance = new Singleton();
				}
			}finally{
				lock.unlock();
			}
		}

		return sInstance;

	}
//.. other code.
}
50 楼 redhat 2009-06-08  
首先要看看你的类是否需要其他oo特性,简单来说,一些工具类,如StringUtils等,不需要太多继承,也不需要其他继承等,那么就没有必要,就看你的是否需要。

另外,一般StringUtils是abstract final的,否则不能保证是单例,我可以直接new 一个出来(这是一个漏洞),参见spring的StringUtils。
49 楼 步行者 2009-06-08  
Saito 写道
ms .. 你没看懂我给你的回复. .

  请看你引用我的回复.. 

  我再次强调. AnotherSingleton 能不能实例化没关系.. 理由同Math ..

  似乎楼主还在为自己创造了一个新的模式而欣喜 . 一种介乎与Singleton跟Monostate的新模式. 实际上掉入了Monostate 能实例化跟不能实例化的怪圈. 实际上Monostate没人傻到要去实例化他. 当然. 你去private他也是有好处的. 告诫别人别做傻事.


我问你 Math 有内部私有状态吗
其他的不多说了

我不是创建模式 而是讨论模式

48 楼 Saito 2009-06-08  
ms .. 你没看懂我给你的回复. .

  请看你引用我的回复.. 

  我再次强调. AnotherSingleton 能不能实例化没关系.. 理由同Math ..

  似乎楼主还在为自己创造了一个新的模式而欣喜 . 一种介乎与Singleton跟Monostate的新模式. 实际上掉入了Monostate 能实例化跟不能实例化的怪圈. 实际上Monostate没人傻到要去实例化他. 当然. 你去private他也是有好处的. 告诫别人别做傻事.
47 楼 步行者 2009-06-08  
Saito 写道


   你的AnotherSingleton无论私有或共有. 实际上是没有任何意义的.

   既然他们是相同的. 那你去实例化多个有什么意义.  唯一的好处是给别人提醒一下. 别浪费. 但是一般看了api的人应该都不会那么傻. .

   就跟你见过有人有事没事就实例化几个Math么?

   全局的应用状态. 一般这样来说. 对象是可以保存状态的. 而Math这种东西一般没有状态. 这也是Singleton跟Monostate的最根本区别.  Singleton我是用来用他那个instance的. 而Monostate.我用的只是那个class.  .




注意 AnotherSingleton 不能实例化
而 MonoState 是可以用来实例化的
如果MonoState 不能实例化 那他就和
AnotherSingleton 一样的了

关于AnotherSingleton 和MonoState
的设计动机 请看我上次给你的回复

相关推荐

Global site tag (gtag.js) - Google Analytics