`
步行者
  • 浏览: 167572 次
  • 性别: 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
	}
}

 

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

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

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

但是不允许实例化,

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

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

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

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


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

而 类 不能。

 

 

 

分享到:
评论
106 楼 徐风子 2009-09-03  
以前喜欢用静态类,不过现在较多用单例了。

首先从定义上说,静态类是违反面向对象原则的(书上看的,至于有什么问题暂时还没想清楚 ^_^),面向对象的原则是任何事物皆属于对象,静态类属于哪一个对象?

单例操作起来是很方便,
像接口,比如A、B 两个单例,同实现一个接口I,我可以在参数类型I中任选一个传递,这是静态类无法实现的。

还有代理,如果我要给一个单例的所有方法加一个缓存代理(实际应用中一种很常见的优化技术,缓存代理肯定是公共方法)。静态类就无法实现。

当然上面这些你可以用其他方法实现,但毕竟很麻烦,设计不就是为了简单易读吗。

如果你暂时不需要这些功能,也不能保证以后不会扩展到这个功能,所以…… 用单例吧。

哦,只私有化构造函数是无法保证单例的,因为有反射,要在构造方法里面加上throw才行。
105 楼 solonote 2009-09-02  
Singleton 模式随着容器的出现,也渐渐走出历史舞台了
104 楼 MVC2008MVC 2009-08-19  
静态类的方法只能调用静态的。而非静态的方法都可以调用的。
103 楼 javatestoracle 2009-08-17  
我认为要不要单例有以下几个因素决定的

    1: 这个类的实例是不是要频繁的被使用,并且里面成员变量是不会改变,或者很少改变的
        如果要遇到以上情况,使用单例是个不错的选择

    2: 第二 ,这个类,是不是会参与到多态中来, 如果要参与多态,那么就要放弃单例的写法

   
102 楼 michael.softtech 2009-07-31  
谨慎发表一下我的观点:

使用对象的情况:
   如果不用单例,那么他就是一个普通对象,不排除有人获取另一个对象,那么如果这个单例是有状态的,并且需要保持这个状态的唯一性,那么多个对象就会出现问题


使用静态类情况:
   类中静态变量是以开始就加载的,而单例是需要时分配堆。如果系统中有很多地方可能需要单例,那么应用一启动就加载这些类,会不会影响性能哪?
101 楼 mark_wang_9527 2009-07-31  
<div class="quote_title">ninini 写道</div>
<div class="quote_div">
<div class="quote_title">wy19280469 写道</div>
<div class="quote_div">
<br>对象创建也需要加载类啊  --&gt; 不是同一个内存空间  而static 只创建一个内存空间   对象创建是new 的过程<br>static 不用吧。<br><br>static 也支持并发啊  --&gt; 如果定义static 属性的话  怎样保证并发的安全性? 同一个地址 你调用时一个值 如果你改变了这个值的时候 ,那下一个人调用的时候 还以为是原来的值怎么办?<br><br>
</div>
<p> </p>
<p>??? </p>
<p>创建一了类的对象首先要加载相应类,当然只需要加载一次</p>
<p>static 可以保持线程同步,跟非static是一个道理啊</p>
<p> </p>
</div>
<p>现在不是多核处理器了么,Static应该不像提倡Moore的单核时代了,Singleton,Static不向以前那么安全了,单核时候可以是同步,毕竟CPU只能在同一时间处理同一任务,多核的话就能同时处理CPU数量的任务,.NET里面都有控制各处理器处理指定线程的基础库,JAVA里面应该也有吧(暂时没找到)</p>
100 楼 mark_wang_9527 2009-07-30  
<div class="quote_title">步行者 写道</div>
<div class="quote_div">
<p><span style="font-size: small;">为什么需要 单例设计模式(Singleton)?</span> </p>
<p><span style="font-size: small;">像下面的一个单例</span> </p>
<p> </p>
<pre name="code" class="java">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
}
}</pre>
<p><span style="font-size: small;"><br></span></p>
<p><span style="font-size: small;">它要实现的主要目标,就是在一个应用中只维护一个Singleton实例 </span></p>
<p><span style="font-size: small;">但一个类在一个应用中也是唯一的,为什么不能直接以类作为单例呢?</span> </p>
<p> </p>
<pre name="code" class="java">public final class AnotherSingleton{
private AnotherSingleton(){}
public static synchronized void doSomething(){
//do something
}
}</pre>
<p> </p>
<p><span style="font-size: small;">把类的所有方法都改为静态方法,</span> </p>
<p><span style="font-size: small;">所有属性都改为静态属性(我们可以把</span> </p>
<p><span style="font-size: small;">静态属性看成类的内部状态),</span> </p>
<p><span style="font-size: small;">但是不允许实例化,</span> </p>
<p><span style="font-size: small;">对类的操作相当于对单例的操作</span> </p>
<p><span style="font-size: small;">而且类也可以维护内部状态(通过静态私有属性)</span> </p>
<p><span style="font-size: small;">这完全满足了单例的要求。</span> </p>
<p><span style="font-size: small;">不知道为什么需要单例模式。。。</span> </p>
<p><span style="font-size: small;"><br></span></p>
<p><span style="font-size: small;">因为我想不出来在什么情况下 单例可以满足需求</span> </p>
<p><span style="font-size: small;">而 类 不能。</span> </p>
<p> </p>
<p>面向对象原则,违背封装跟多态,静态本来就违背面向对象原则,即为面向过程,正如楼上说的不如写C</p>
<p>PS:楼主这代码也不算是一个绝对的单例,1.采用反射机制可以创建多个实例 2.未重写readReslove方法,反序列化产生2个实例 3.建议用枚举来做单例以上两种问题均已解决 4.同步方法改为Volatile跟块双重锁更佳</p>
<p> </p>
<p> </p>
<p> </p>
</div>
<p> </p>
99 楼 ninini 2009-06-14  
<div class="quote_title">wy19280469 写道</div>
<div class="quote_div">
<br>对象创建也需要加载类啊  --&gt; 不是同一个内存空间  而static 只创建一个内存空间   对象创建是new 的过程<br>static 不用吧。<br><br>static 也支持并发啊  --&gt; 如果定义static 属性的话  怎样保证并发的安全性? 同一个地址 你调用时一个值 如果你改变了这个值的时候 ,那下一个人调用的时候 还以为是原来的值怎么办?<br><br>
</div>
<p> </p>
<p>??? </p>
<p>创建一了类的对象首先要加载相应类,当然只需要加载一次</p>
<p>static 可以保持线程同步,跟非static是一个道理啊</p>
<p> </p>
98 楼 wy19280469 2009-06-14  
ninini 写道
wy19280469 写道
如果什么都定义STATIC
那在类加载的时候 内存得被占用多少呢?
如果属性被定义成STATIC
那在发生并发的时候如何避免数据准确呢?
如果类都定义成STATIC
那这个类如何重用呢?意思是说这个类同时被多个调用

我只有在数据唯一确定不变的情况下 来做STATIC 例如数据库连接

其他的要视情况而定~

例如管理Hibernate的Session 就会用到ThreadLocal 也会被定义成Static 因为就需要使用一个。

我怎么感觉你说的都不对啊???
? 1,对象创建也需要加载类啊
? 2,static也支持并发啊
? 3,类可以同时被多个调用啊



对象创建也需要加载类啊  --> 不是同一个内存空间  而static 只创建一个内存空间   对象创建是new 的过程
static 不用吧。

static 也支持并发啊  --> 如果定义static 属性的话  怎样保证并发的安全性? 同一个地址 你调用时一个值 如果你改变了这个值的时候 ,那下一个人调用的时候 还以为是原来的值怎么办?

97 楼 ninini 2009-06-14  
wy19280469 写道
如果什么都定义STATIC
那在类加载的时候 内存得被占用多少呢?
如果属性被定义成STATIC
那在发生并发的时候如何避免数据准确呢?
如果类都定义成STATIC
那这个类如何重用呢?意思是说这个类同时被多个调用

我只有在数据唯一确定不变的情况下 来做STATIC 例如数据库连接

其他的要视情况而定~

例如管理Hibernate的Session 就会用到ThreadLocal 也会被定义成Static 因为就需要使用一个。

我怎么感觉你说的都不对啊???
? 1,对象创建也需要加载类啊
? 2,static也支持并发啊
? 3,类可以同时被多个调用啊
96 楼 wy19280469 2009-06-14  
如果什么都定义STATIC
那在类加载的时候 内存得被占用多少呢?
如果属性被定义成STATIC
那在发生并发的时候如何避免数据准确呢?
如果类都定义成STATIC
那这个类如何重用呢?意思是说这个类同时被多个调用

我只有在数据唯一确定不变的情况下 来做STATIC 例如数据库连接

其他的要视情况而定~~~

例如管理Hibernate的Session 就会用到ThreadLocal 也会被定义成Static 因为就需要使用一个。
95 楼 步行者 2009-06-13  
fjlyxx 写道
唉,讨论了这么多.单例的实现已经很完美了,不需要再多的优化了,但是这种单例只限于同一个jvm 如果我是一个分布式系统 或者不同JVM LZ你又打算如何实现呢?


分布式系统 共享一个单例,
如果以对象方式实现 这种单例的 一致性,应该是当
分布式系统中的一个节点 的单例 发生状态改变时,
更新所有节点相应单例的状态,可能一种实现方案就是
通过对象 序列化
虽然类不能 序列化,但它的 静态属性 是可以存储并恢复的,
这也可以解决 AnotherSingleton 在分布式系统下的一致性问题。


94 楼 fjlyxx 2009-06-13  
唉,讨论了这么多.单例的实现已经很完美了,不需要再多的优化了,但是这种单例只限于同一个jvm 如果我是一个分布式系统 或者不同JVM LZ你又打算如何实现呢?
93 楼 jansel 2009-06-12  
两种单例的实现而已,都是单例。如果从单例看的话,两者没有区别。
92 楼 步行者 2009-06-12  
幸存者 写道
一些显而易见的好处是Singleton可以赋值,可以当成参数或返回值传来传去,多个Singleton可以共同实现某个接口而实现多态。

“可以当成参数或返回值传来传去”
这是对象的好处 ,但如果对象是单例,就另当别论了!
不过我们引用Singleton的时候,
好像大多是以这种方式
Singleton singleton = Singleton.getInstance();
那么既然 通过 这种方式就可以引用到 单例
我们 还需要把它作为输入输出,
在方法中作为参数进行引用吗,
单例 只有一个,
所以把它作为参数 和 像上面的方式写在方法里 来获取Singleton,
应该没有区别
那么 何必 把Singleton写在参数列表里呢,因为怎么传都只有它一个

但如果多个Singleton共同实现了某个接口而实现多态。
那么 作为参数或返回值传来传去 就变得有意义了
是一个优势 !!!
不过感觉有点弱(多个Singleton共同实现了某个接口)
91 楼 幸存者 2009-06-11  
一些显而易见的好处是Singleton可以赋值,可以当成参数或返回值传来传去,多个Singleton可以共同实现某个接口而实现多态。
90 楼 步行者 2009-06-11  
qzzlw 写道

类是什么呢?类只不过是方法和数据的集合,方法都在代码段,这部分内存是不可能省掉的。数据如果是静态的,就在全局数据段,这部分永远会加载到内存。实例数据只有在构造类实例的时候才占有堆内存。



我承认 “数据如果是静态的,就在全局数据段”
这部分在类被加载时才会被加载到内存
89 楼 qzzlw 2009-06-11  
步行者 写道
qzzlw 写道
步行者 写道
qzzlw 写道
类的属性是全局的,系统一启动就已经在全局静态数据区分配好了资源,而单例是对象,只有在需要的时候才在堆内分配资源来放置实例属性。从封装的角度或者资源占用的角度来看 ,单例可能会更好一些。


类不是在系统一启动时就加载,而是在第一次引用,或实例化时进行加载
还有另一种方法加载类
Class.forName("XXX");
反而对象的初始化要先加载类,
再进行实例化。
所以我觉得从资源占用的角度来看 ,类反而要好一些。

至于封装,也可以通过私有静态属性来封装类状态,
我觉得这也不是问题




我说的是属性,不是类加载的问题。静态的属性肯定是放在全局数据段,而且一直占用,实例属性是在堆中需要的时候分配的。我这是从PE文件结构来理解的,java虚拟机应该也差不多。


静态属性也是在需要的时候被加载进内存的啊 
静态属性不是定义在类中吗
类加载后 类的属性才能被放在全局数据段中

实例属性 也只有实例被创建后才能被保存到堆中
但首先也需要加载相应的类



类是什么呢?类只不过是方法和数据的集合,方法都在代码段,这部分内存是不可能省掉的。数据如果是静态的,就在全局数据段,这部分永远会加载到内存。实例数据只有在构造类实例的时候才占有堆内存。
88 楼 步行者 2009-06-11  
qzzlw 写道
步行者 写道
qzzlw 写道
类的属性是全局的,系统一启动就已经在全局静态数据区分配好了资源,而单例是对象,只有在需要的时候才在堆内分配资源来放置实例属性。从封装的角度或者资源占用的角度来看 ,单例可能会更好一些。


类不是在系统一启动时就加载,而是在第一次引用,或实例化时进行加载
还有另一种方法加载类
Class.forName("XXX");
反而对象的初始化要先加载类,
再进行实例化。
所以我觉得从资源占用的角度来看 ,类反而要好一些。

至于封装,也可以通过私有静态属性来封装类状态,
我觉得这也不是问题




我说的是属性,不是类加载的问题。静态的属性肯定是放在全局数据段,而且一直占用,实例属性是在堆中需要的时候分配的。我这是从PE文件结构来理解的,java虚拟机应该也差不多。


静态属性也是在需要的时候被加载进内存的啊 
静态属性不是定义在类中吗
类加载后 类的属性才能被放在全局数据段中

实例属性 也只有实例被创建后才能被保存到堆中
但首先也需要加载相应的类


87 楼 qzzlw 2009-06-11  
步行者 写道
qzzlw 写道
类的属性是全局的,系统一启动就已经在全局静态数据区分配好了资源,而单例是对象,只有在需要的时候才在堆内分配资源来放置实例属性。从封装的角度或者资源占用的角度来看 ,单例可能会更好一些。


类不是在系统一启动时就加载,而是在第一次引用,或实例化时进行加载
还有另一种方法加载类
Class.forName("XXX");
反而对象的初始化要先加载类,
再进行实例化。
所以我觉得从资源占用的角度来看 ,类反而要好一些。

至于封装,也可以通过私有静态属性来封装类状态,
我觉得这也不是问题




我说的是属性,不是类加载的问题。静态的属性肯定是放在全局数据段,而且一直占用,实例属性是在堆中需要的时候分配的。我这是从PE文件结构来理解的,java虚拟机应该也差不多。

相关推荐

Global site tag (gtag.js) - Google Analytics