作者 内容
 smilemac  关于多态实现Singleton模式的探讨 --smilemac
 

题记:我本人也不是很喜欢这个解决办法,但有人问起,并且资料中没有发现其他类
似解法,所以整理成文,供大家参考讨论.

关于多态实现Singleton模式的探讨

--smilemac

Singleton模式虽然简单,但却是被讨论最多的一个模式,为什么呢?并不是概念问题,而是算法问题。具体说就是singleton对象生命期和作用域的管理算法问题,在不同的场景下会有不同的需要,而结构设计的意义在于将可能发生变化的部分彼此隔离开来,使他们能够独立的在各自的轴上发生改变,减少彼此的耦合,所以将一个可能发生争论的算法隔离于具体的应用环境是有意义的。


如何实现Singleton模式的可重用性,即如果有若干个类都需要实现Singleton,那么
如何才能避免每一个类都必须拥有一个独立的Singleton算法的拷贝呢?能否所有
类共用一个拷贝,这样,如果需要改算法只改一处就可以了.更进一步,能否在不同的
项目中重用这个算法呢?

在C++中,大师Andrei Alexandrescu已给出非常好的解决办法, 但是在一个不支持
模板的语言中,如何只使用一些基本技术,如类的封装和运行期多态技术,来实现可
重用的Singleton模式库呢? 本文试图给出一种下面这段代码所示的解决办法.

[
这段代码用伪java写成:),由于笔者对于java非常不熟,所以只好是伪java,请读者
海涵. 感谢网友henry_zhou提出的问题,使我有机会思考. 这种解决办法也可能不
对,所以请大家指出以一起探讨正确的答案.如转载讨论,也请注明出处.

同时由于笔者对java的泛型支持程度不太了解,因此不排除java里有更好的解决方
案.本文仅假设语言可提供的支持只是最基本的面向对象特征.
]

//package1;
class Singleton
{
| protected Singleton _instance;
| public Singleton(Singleton _inst)
| {
| _instance = _inst;
| }
| public virtual Singleton getInstance()
| {
| if (_instance.get() == null)
| _instance.create();
| return _instance.get();
| }
| protected virtual Singleton get()
| {
| //error handler code;
| }
| protected virtual void create()
| {
| //error handler code;
| }
}

//e.g.,a thread-safe singleton implematation.
class SingletonThreadSafe : public Singleton
{
| public SingletonThreadSafe(Singleton _inst);
| public virtual synchronized Singleton getInstance()
| {
| if (_instance.get() == null)
| _instance.create();
| return _instance.get();
| }
}

//package2
class MyBaseClass : public Singleton
{
| protected MyBaseClass();
| ......
}

class Instance_base : public Singleton
{
| private static MyBaseClass _instance;
| public Instance_base(){};
| protected virtual MyBaseClass get()
| {
| return _instance;
| }
| protected virtual void create()
| {
| if (_instance == null)
| _instance = new MyBaseClass;
| }
|
}

//package3; e.g., a subclass
class MySubClassXXX : public MySubClass
{
| protected MySubClassXXX();
| ......
}

class Instance_XXX : public Instance_base
{
| private static MySubClassXXX _instance;
| public Instance_base(){};
| protected virtual MySubClassXXX get()
| {
| return _instance;
| }
| protected virtual void create()
| {
| if (_instance == null)
| _instance = new MySubClassXXX;
| }
|
}

//client;
Singleton singGen = new SingletonThreadSafe(new Instance_XXX());
MySubClassXXX myObj = down_cast(singGen.getInstance());

这段代码利用了所谓class-oriented语言的一个特点:同一个类的对象可以相互访
问彼此的内部成员,即访问控制是在类一级,而非对象一级.而在java中,访问控制则
是放宽到同一个package.这样,我们就可以将get和create这些可能使singleton崩
溃的函数设计为protected.

对于每一个用户子类,都需要实现它的instance类,这其实是一个instance
holder.在大多数的Singleton的实现代码中,instance holder是与用户类合在一
起的.在这里,如果用户子类可以以低成本来创建一个安全的对象,所谓安全,是指创
建不会影响singleton实例对象,而所谓低成本,是指初始化的代价可以接受,如果
这些条件都满足,那么也可以将instance holder并入用户类中,使用时用特定的构
造函数创建一个哑元来代替new Instance_XXX().但分开可能更具一般意义.

这样,Singleton和SingletonThreadSafe都是可重用的,并且这棵继承树可以自行扩展. 提供不同scope下的Singleton, 如thread scope singleton(在使用多线程的并发服务器中用),process scope singleton, system scope singleton, DCE scope singleton等等,或基于其他考虑的,如特定机器,效率等因素的singleton。

从本文中也可看到,Singleton模式的关键在必须有instance holder. 所以其他如
getInstance()函数是否静态,则不是必须(这是不少网友对singleton模式的误解
).一旦理解这一点,其实剩下的就比较容易了.但这种方法有一个不足之处,就是必
须使用难看的downcast.

最后补充说一下,不少人理解的可重用性就是copy/paste,或者需要少量
refactory的重用,而真正理想的可重用性是非侵入性的.本文试图给出的也是这样
一个方案.

 03/06/26 14:50 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  补充说一下,不少人理解的可重用性就是copy/paste,或者需要少量 refactory的重用,而真正理想的可重用性是非侵入性的.本文试图给出的也是这样一个方案
 
 03/06/26 18:40 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 sealw  非侵入式的重用还有一种解释,就是基于二进制码和重用,或者说基于组件开发
 

小粒度的组件(做的事少,或功能点少)重用的机会多,但利用小粒度组件创建应用的工作量大;

大粒度组件(功能点多)重用的机会少,不够灵活,但重用将减少很多工作量;

所以建议大粒度组件仍由一些小粒度组件构成。

比较郁闷的是明知道某个软件中包含某个功能,一查看代码,却发现它不可重用。完全是面向对象版的意大利细面条程序。表示逻辑、应用逻辑、业务逻辑、数据访问逻辑混在一起,密不可分。

理想的重用是不用查看、修改源代码的重用。

 03/06/27 08:53 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 joy_wind  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

Singleton模式是为了保证某个类在整个系统中的唯一实例,但一般的Singleton实现方法难以实现多态,为了解决这一问题,可以单独写一个SingletonCollection类,它是所有要实现唯一实例的类的容器,是实际的Singleton,而其他类可以按普通的java类来实现(可以多态)。这样做也挺简单的。

 03/06/27 10:17 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 zhxb   回复: 关于多态实现Singleton模式的探讨 --smilemac
 

我觉得可能用这种方式,但我认为,每个子类也不会减少一两行代码。如果是在一个系统中,通过构造型模式来统一构造多种类型的Singleton才会比较有意义,否则不是很有必要。
另外,对于子类的构造方法定义为Public,我认为已经失去了Singleton的目的,就可以创建多个类的实例了。再则,如果get方法没有定义为Public Static,即没有定义为类的方法,其它类也不能调用。

 03/06/27 11:10 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 frankwoo  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

although it can solve some problem, but somehow it is kind of tedious and not so beautiful.
in contrast with factory-register model, at least this approach forces every subclass cohere with an instance class, cos the inner static attribute.
why not use a simple register-factory pattern for example no matter which language u use?
--I still think this is not a good idea, if this means singleton pattern of virtual construtor, then I definitely think that is not good comparing with other choices.

 03/06/27 11:27 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

in contrast with factory-register model, at least this approach forces every subclass cohere with an instance class, cos the inner static attribute.

[
factory-register model 或者需要为每个子类生成一个factory,或者需要一个switch-case语句,同时还加上package dependance.

需要伴随一个instance class的实质原因不是static,而是因为类型匹配问题。你也可在一个全局表中存放,但那是画蛇添足之举。

而且,instance class是一个极其简单的类,简单至你想犯点错误都需要故意才行,但factory却可能简单,也可能复杂。如果你喜欢,你也可将instance class叫做factory.
]

why not use a simple register-factory pattern for example no matter which language u use?
--I still think this is not a good idea, if this means singleton pattern of virtual construtor, then I definitely think that is not good comparing with other choices.

看来我们观点不太相同,对我来说,我宁愿在每增加一个新的子类时,费点事多写几行简单的代码,也不愿去在一个switch-case里增加一个case子句,那是最容易引入bug的,同理,我宁愿写一个新的类,也不愿去refactory一个已经完成的if语句。所以,我觉得在任何情况下,如果没有函数指针,没有dynamic class loading, register方法都不是一种好方法。说实话,我实在不明白lookup有什么好处。



另外呢,Singleton模式虽然简单,但却是被讨论最多的一个模式,为什么呢?并不是概念问题,而是算法问题。所以,我不觉得将一个可能发生争论的算法放在两个函数里(getInstance, lookup)是一个好主意,也不认为将这样的算法到处copy/paste是个好主意,而这正是我这篇短文试图解决的。

 03/06/27 13:57 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

可能减少不了代码,但可以减少复杂算法的代码。

哪个子类的构造函数是public的?好像没有的说。
 

 03/06/27 14:01 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  呵呵,我觉得类库比组件重用更实际一些。我不喜欢VB之类用鼠标编程的编程方式。
 
 03/06/27 14:10 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou   回复: 关于多态实现Singleton模式的探讨 --smilemac
 

我觉得从统一算法的角度考虑这的确算是个比较通用的解决方案(但对于C#、Java这种可以动态加载类的语言来说直接在工厂类中实现不知是不是会更方便),但如果仅仅是从为了相同接口及实现不想重复编写的角度来看(可能我这是属于比较低层次的要求),可能并不是一个好的方案,因为这个方案大大增加了代码量(相对于直接在每个类中实现来说),同时每次获取实例都是以产生一个辅助类的对象为代价(当然代价比较小)。

 03/06/27 17:24 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

其实这种方案适用的地方比你所想的还要小,java一定有更好的方案,但应该不
是factory.

这种方案文中也讲了,只适用于一些比较简单的或不成熟的oo语言
.

第二,为什么我不赞成singleton factory方案呢? 其实这和singleton的应用
有关,任何设计里,如果有很多singleton类,那么你需要作的首先是检查一下设
计是否合理. 另外,即使需要singleton, singleton factory也不见的必要,因为
instance holder并不是singleton范式的问题焦点,焦点在算法上.

第三,文中也说了,你如果不喜欢类太多,也可以将instance holder合并到用户
类里,但可能比较难看一点.

第四,如果你作第二,第三个项目, 这样的类库可以直接重用,不需要再为写
singleton而烦恼,你若作过并发程序或分布式程序,写singleton比你想像的要
难.尤其当你需要考虑效率的时候.

最后,我以前有一个同事,他严禁他的程序员copy/paste,哪怕一模一样的代码
,也要手工敲进去.呵呵,他是个很优秀的pm.

所以, 你的问题首先我想是设计问题,第二,出发点不同,选择也不同.取决于你的兴
趣和对问题前景的预测. 这个设计其实我也不想写出来,因为我工作用的主要是
C++,但你们不停的问,呵呵....

 03/06/27 17:51 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

[[第二,为什么我不赞成singleton factory方案呢? 其实这和singleton的应用
有关,任何设计里,如果有很多singleton类,那么你需要作的首先是检查一下设
计是否合理. ]]

我们现在就有很多类专门用于对各种对象进行数据库的操作的,对象是通过参数传进去的,这些类本身并没有什么属性,相当于工具类,我想把这些类做成单态的,而且我感觉也不需要考虑线程同步的问题(数据库连接由连接池去管理了,当然获取实例的函数需要考虑同步,主要是为了防止new一个实例的时候出问题)。听你这么讲这种这么多单态类设计是不是有问题?

[[你若作过并发程序或分布式程序,写singleton比你想像的要
难.尤其当你需要考虑效率的时候.]]

我没真正做过并发程序或分布式程序。
为什么实现成singleton会影响效率?

 03/06/27 18:13 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  仔细看了一下,发现不太明白你的意思。收回我前面的回复。:)
 
 03/06/27 19:57 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

如果你是单线程的,不需要考虑线程安全。那个设计改成一个singleton类可能好一些。其实也许不需要singleton。

天下没有免费的午餐,singleton在很多情况下是需要付出代价的,即使在单线程模式下。我的观点是:任何时刻可以不用singleton就不用。

其实确实没有绝对最佳的singleton实现,都有适用范围,都是解决某一类问题的。

 03/06/27 20:18 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 sealw  那叫交互式设计,写EJB和com+并把它们组织成应用叫做基于组件开发
 
 03/06/27 21:16 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  是吗?谢谢纠正。我以为控件也是一种组件呢。
 

ejb没用过,com+也没用过,只用过dcom,很早了,印象不是太好,主要是因为水平不高,又没有资料,所以用的很差。不过我想起以前似乎组件提的很响,后来不怎么说了,现在怎么样,有前途吗?

 03/06/27 22:07 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

singleton提供了访问全局更优雅的方法,要避免使用singleton似乎很难,而且至少它的可读性比较强。

>最后,我以前有一个同事,他严禁他的程序员copy/paste,哪怕一模一样的代码
>,也要手工敲进去.呵呵,他是个很优秀的pm.

这是出于什么目的呢?为了让他们不再c/p,或是检查错误?

 03/06/27 23:31 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  该用的时候自然要用,不过相信有很多使用了singleton的设计是不必要的。
 
 03/06/27 23:41 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 sealw  象VB或Delphi也利用到了组件的优点,主要利用表示层组件,复用了表示层逻辑
 

而这种复用明显地带来了界面开发的效率和品质。

对于业务组件和数据访问组件的复用,可借鉴的成功经验还不多。这对于企业级开发确实是必要的,所以这些软件巨头们才会开发出这些技术,因为他们比我们更深刻地认识到企业应用的需求。

CORBA/J2EE/COM+,目标是提供一些可以实现非侵扰式改变的业务组件,特别是可以在二进制的基础上复用这些组件。带来的好处是不必查看源代码,不必找出需要修改的源代码,也不必改动源代码,就能实现复用。

基于组件开发更强调接口设计,更强调表示逻辑、业务逻辑和数据访问逻辑的分离,更强调组件的上下文无关性和可定制性。从而更能够复用。

在业务组件的复用方面,远没有表示逻辑组件这么成功,但这正是业界努力的方向。

大牛说,复用是已知唯一一种实现令人满意的开发效率和品质的方法。

 03/06/28 09:32 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 象VB或Delphi也利用到了组件的优点,主要利用表示层组件,复用了表示层逻辑
 

我觉得CORBA/J2EE/COM+的目标不是复用。

 03/06/28 10:10 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

我昨天差资料看到一个关于singleton模式的介绍,是用c++写的,我明白了为什么你说有时候实现起来会很麻烦,而且在c++中如果要考虑线程同步和执行效率的确也挺麻烦的。
但是c++中的这些问题好像在c#、java中都不存在了,因为只要通过如下声明就行了:private static Singleton _instance = new Singleton();
在getInstance的时候就不用进行线程的同步了,也就不存在并发等待的情况,因此在java、c#中实现成singleton的代价相对来说是很小的。
我看到一个用java写的通过在父类中进行注册的方式实现的可继承单态模式,觉得这种实现方式还不错,算法也是统一封装的,但缺点是可能只有象java、c#这种可以动态加载类的语言才好用,而且子类并不是严格意义上的singleton类,因为子类的构造函数是public的(好像你的方案也存在这种问题,可能是共性无法解决的。在java中,如果把子类构造函数可见性设成缺省的包内可见,这样在包外就无法直接实例化子类了,不知这样是否可行?但其他语言好像没办法了)

 03/06/28 10:40 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  我那个方案里用户子类的构造不是public。
 

首先我那个方案里用户子类的构造不是public。

java里有singleton描述子吗?如果那样,其实是剥夺了你自己定制算法的权利。

在没有函数指针的条件下,只能是动态加载类的方法,但时间开销恐怕不小。

“考虑线程同步和执行效率”与语言没有必然关系。不过似乎做java程序的很少考虑效率这回事。

 03/06/28 10:49 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 我那个方案里用户子类的构造不是public。
 

java中没有singleton描述子,我写singleton作为类明只是想说这个类要设计成singleton,可能换个类名更合适

你原来的部分代码如下:
[[
//package3;
class MySubClassXXX : public MySubClass
{
......
}

class Instance_XXX : public Instance_base
{
private static MySubClassXXX _instance;
public Instance_base(){};
protected virtual MySubClassXXX get()
{
return _instance;
}
protected virtual void create()
{
if (_instance == null)
_instance = new MySubClassXXX;
}

}
]]

如果MySubClassXXX类的构造函数不是public的,你如何在别的类中去new它?

至于“考虑线程同步和执行效率”我可能表达的不清楚,在c++中singleton模式好像只能在getinstance接口中去实例化类,那么就必须考虑线程的同步问题,这就带来线程等待,会影响执行效率;在java或c#中就可以不用这么做。只是动态加载类的确时间开销较大。
但不知道这种开销对系统运行效率影响有多大?好像sun的petstore例子中工厂模式就大量使用了这种方法

 03/06/28 11:07 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 我那个方案里用户子类的构造不是public。
 

对不起,原文中我可能没有说清楚,用了省略号,但在文字部分中做了说明,以为大家能明白。但看来没表达好,所以我对原文做了修改,请参看。


访问文件系统,然后从硬盘上现加载一个类文件,你说有多高效率呢?

 03/06/28 11:19 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  另外需不需要线程安全与java new还是C++ new没有关系,与怎么new也没有关系。
 
 03/06/28 11:28 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 我那个方案里用户子类的构造不是public。
 

[[//package3; e.g., a subclass
class MySubClassXXX : public MySubClass
{
| protected MySubClassXXX();
| ......
}

class Instance_XXX : public Instance_base
{
| private static MySubClassXXX _instance;
| public Instance_base(){};
| protected virtual MySubClassXXX get()
| {
| return _instance;
| }
| protected virtual void create()
| {
| if (_instance == null)
| _instance = new MySubClassXXX;
| }
|
}
]]

我还是不明白,类Instance_XXX不是从类MySubClassXXX继承的,如何使用类MySubClassXXX的protected构造函数?

 03/06/28 16:57 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 另外需不需要线程安全与java new还是C++ new没有关系,与怎么new也没有关系。
 

你没明白我的意思,在java中可以在定义中直接new,如:
public class MySingleton{
private static MySingleton _instance = new MySingleton();

private MySingleton(){}

public static MySingleton getInstance(){return _instance;}
}

但在c++中就必须在getInstance函数中new,不能在定义时初使化,所以c++实现的getInstance必须考虑线程同步,而java用上述方法就不需要考虑线程的同步就

 03/06/28 17:01 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  java的protected是package内公开和对子类公开
 

缺省只要在同一个目录下就没有问题。
当然不能算好的singleton,不过编译应该没有问题

 03/06/28 18:02 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  这只是线程安全的一个简单例子,皮毛而已
 

单纯说到对class的static成员初始化的问题,java固然可以直接在类定义里设,c++目前版本尚不支持直接在类定义里设,不过在类定义外初始化也没有任何问题。
这个并不重要,用这个例子不过方便说明问题罢了

 03/06/28 18:08 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  程序不好看。在c++里如果不用template能有好办法吗?我觉得解决可能容易,要漂亮困难
 
 03/06/28 18:11 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  回复: 该用的时候自然要用,不过相信有很多使用了singleton的设计是不必要的。
 

应该不会这么绝对,GoF里的一些模式就是和singleton有关系的
如果不需要直到需要时才实例化,用个静态成员来实现instance,这样开销也不会太大

 03/06/28 19:52 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 sealw  你说它们的目标是骗钱也是可以的
 
 03/06/28 19:55 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  不是时间开销上的问题。
 
 03/06/28 22:57 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  很高兴大家提出这么多意见,但不知可否给出其他更好的做法。谢谢。
 
 03/06/29 11:30 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  那是?
 
 03/06/29 11:52 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  不太懂java, 感觉这段程序有可能是错的,不过手头没有书,不好说,但收回前面的回复。
 

不太清楚java对静态函数调用的处理方式。不过感觉这段程序即使在单线程模式下是正确的,但是在多线程模式下也一定是错的。

 03/06/29 20:24 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  回复: 那是?
 

有很多问题,不过首先最重要的一点是你这种方法是错的。

 03/06/29 22:25 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  回复: 那是?
 

哦?
>有很多问题
是哪些问题?能列举一下吗?
>不过首先最重要的一点是你这种方法是错的
很想知道原因

 03/06/29 23:25 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  至少在C++里,静态变量的初始化顺序没有明确定义
 

直接用静态对象可能造成某个初期设定时用到了尚未初始化的对象。
当然这个问题不考虑也可以,隐患而已

 03/06/30 00:08 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  java这样是可以的,当然是线程不安全的
 

说c++不用template,是因为我认为如果c++有不用template也能得到的漂亮做法,java就很有可能也可以。如果c++非template不行,java要得到漂亮解决的可能性就接近于0
说实话,这样做下去,原本为了每个类几行的重复想避免,现在反而要增加类,恐怕更是复杂。
c++的template方案其实可以理解为是一次书写,自动增加相关类,把那些在java里的重复操作避免了,实质还是增加了类的数量
这种问题上,我不认为java会有比c++更好的解决,即便不考虑template

 03/06/30 00:18 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  回复: 至少在C++里,静态变量的初始化顺序没有明确定义
 

这个在类里的静态成员变量又没有依赖关系,跟初始化顺序应该没有关系吧

 03/06/30 11:09 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 frankwoo  回复: 关于多态实现Singleton模式的探讨 --smilemac
 

最大的区别是,subclass要不要有什么特别要求/处理。
registery模型就是为了构建一个基本的运行frmawork,至于case.switch等问题,实在没必要这么做,系统自己可以在一个factory重处理,更复杂的话,根据meta data自动生成一个abstract factory的instance也可以。
本来virtual constructor就是用来定义framework,不过这里的framework和上边我说的有一点不同,这里的framework是整个框架的top interface,而上面的则是supporting lever。由此引发了一个问题,采用你的方法,要求顶层的设计/programmer对系统地下也很明白,或者严格的约定一些额外的规则。如果是用来做一个产品的话,不太好。做一个应用到问题不大。
virtual constructor实现singleton的方法如果有,我觉得也不应该是这个样子。

 03/06/30 11:44 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: java的protected是package内公开和对子类公开
 

java好像缺省的才是包内可见吧,protected好像只有子类才能访问?(我没有实际做过,但看书上好像是这么说的)

 03/06/30 15:06 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  我是不知道您看得是哪本书,这本书基本上可以扔掉了,
 

请访问java官方说明网页
http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#102765
关键如下
Otherwise, if the member or constructor is declared protected, then access is permitted only when one of the following is true:
Access to the member or constructor occurs from within the package containing the class in which the protected member or constructor is declared.
Access is correct as described in §6.6.2.

 03/06/30 16:58 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  如果这样考虑问题,根本没有必要引入singleton模式
 

要求程序员注意不要书写有依赖性的静态变量初始化和要求程序员在程序中只定义一个唯一的变量作为全局变量在开发管理上基本是一回事。
都是可以简单解决的,也都是需要依靠程序员自己小心回避的。如果出错,都是在运行时。
引入singleton使唯一变量问题不需要程序员再关注了,如果出错会在编译时出现,留下个依赖性隐患也没有大不了的。如果把示例当成实际应用代码看

 03/06/30 17:07 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 henry_zhou  回复: 我是不知道您看得是哪本书,这本书基本上可以扔掉了,
 

非常感谢!
我前两天还特意查了一下书,看来是可以扔掉了。
主要是java我只看过书,没实际做过项目,现在使用c#,所以java有些细微概念理解不深。

 03/06/30 17:08 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 smilemac  说半天原来一直在原地打转
 

我又看了看你的那个程序,我想我看明白了,你的意思是给每个用户子类在
factory里加一个build函数? (其实是给每个子类一个独立的伴随factory,我
问过你,你却说不是,因为这里build函数就是concrete factory)

呵呵, 侵入式结构只有在不得以时才用,因为需要向用户开放源码,还存在引入
bug的隐患.而且就你的解法,不仅没有解决singleton算法的重用问题,还会使
getinstance和buildXXX的算法更复杂,这不是解决问题之道.

metadata? 恐怕用起来更是复杂. 复杂的地方没解决,却将不复杂的地方复杂
化了. 比如,你如何生成一个新类的metadata.

至于约定,你见过不需要任何约定的framework吗? 我是没有见过.

就解法的问题来说,我那个解法的问题在你的里也一个不少,而且更多.除非你非认
为写一个函数比写一个类更简单,那样我就没办法了.:)

建议你先自己按你的思路实现一下,否则你说你的,我说我的,说半天一直在原
地打转.
 

 03/06/30 17:09 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  回复: 如果这样考虑问题,根本没有必要引入singleton模式
 

没有理解上面的话。
在Design Pattern Explained --Alan Shalloway & James R.Trott
里有一段这样的话
If you know you are going to need an object and no performance
issue requires you to defer instantiation of the object until it's
needed, it is usually simpler to have a static member contain a reference to the object.

还是用代码说话吧,我的实现可能是这样的
class Singleton
{
public:
static Singleton* instance()
{
static Singleton instance_;
return &_instance_;
}
protected:
Singleton() {}
...
}
这样实现的singleton的隐患是什么?而smilemac认为"不过首先最重要的一点是你这种方法是错的",这个应该比隐患还要严重的问题是什么?

 03/06/30 17:25 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 killcamel  这个代码我不认为有问题。因为你前面说
 

“如果不需要直到需要时才实例化,用个静态成员来实现instance”
我就理解成你打算用类的静态变量了,因为你现在的代码实质上也是需要时才实例化。而且很少有人把静态函数内静态的局部变量称为静态成员。
理解错误,抱歉。

 03/06/30 17:39 酷帖!    臭帖!    回复  
酷帖评价:           臭帖评价:
返回页首
 xlm2000  hehe,谢谢你的回复
 

看来还是用代码说话比较简洁明了,我都忘了前面的问题是什么了:-)