请教阎博士:是否所有的不变类都可以做成单实例?欢迎讨论

steven_cheng 2004-04-27 12:01:45
这里的不变类指的就是没有可变成员变量的类,这样的类,没有状态,只是提供一些方法。这样的类,是否用单实例实现?如果是在一个多线程环境中调用,性能上有什么样的影响?
...全文
1172 65 打赏 收藏 转发到动态 举报
写回复
用AI写文章
65 条回复
切换为时间正序
请发表友善的回复…
发表回复
byyter 2004-07-03
  • 打赏
  • 举报
回复
单件的适用性:
1。当一个类只能有一个实例而客户可以从一个众所周知的访问点访问它时。
2。当这个唯一的实例应该是通过子类扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
steven_cheng 2004-06-30
  • 打赏
  • 举报
回复
多个JVM保持一个singleton,最重要的就是这些对象的同步。
jeffyan77 2004-06-30
  • 打赏
  • 举报
回复
在多个JVM中保持一个单态的问题,在大型项目中时常出现。我的书中没有直接讨论这个问题,但是书中提到的预定式序列键(多例模式一章)可以用来回避(work around)这个问题。

如果你的单例对象没有重要的可修改状态,那么就没有必要在三个JVM中维护一个单例对象。你这样做一定是因为有重要的状态。如果这个状态是序列键值,不妨使用我书中的答案,使用三个单例对象,但是它们分别预定键值,做到互不冲突。

该问题的解决方案有很多,最简单的是使用数据库,较为复杂的还有使用Directory Server,MQ, RMI, socket等等。我就谈谈我在某个大型系统中的设计。

首先,我们考虑一个已有的架构设计。Directory Server其实就是一个很好的例子,假定这个server含有用户信息,每个用户登陆需要与这个server联络检查用户名、密码以及用户的entitlements(请问中文怎么翻译?)等。你的公司可能有10个系统(每个系统可能有一个或者多个JVM),但用户的信息只有一套,这叫做单点登陆(SSO Single Sign On)。

显然,SSO的架构设计提示我们可以建立第四个JVM,专门保持这个单态。所有的其他JVM使用socket与此JVM保持联络。
jiganghao 2004-06-30
  • 打赏
  • 举报
回复
yes, the idea is simple and clear: set a counter at a place that accessible from 3 JVMs, like file, DB, JMS, Ldap and others like jeffyan77 mentioned. And we might transfer the singlton among them.

For implementation, the same issue is synchronization like in single JMV version.

fwp0794 2004-06-29
  • 打赏
  • 举报
回复
如果只是要使用这个类的一些方法,还是使用static的方式来得好些;另外要防止这个类的实例的胡乱生成,可以把这个类的constructor声明为private。
大家觉得这样如何?
jiganghao 2004-06-29
  • 打赏
  • 举报
回复
an interview question: how to make a singleton in 3 JVMs (i.e., at most 1 intance in 3 JVM)?
shine333 2004-06-29
  • 打赏
  • 举报
回复
太武断了,按照你的定义String, Integer都是的,但没有人想把他们Singleton

IMHO, 不变类的用处就是让你只能看,不能动,任何修改的尝试顶多会产生一个新的实例

而Singleton是让全世界人民都享用唯一一个实例,能不能修改是另外一回事
truezerg 2004-06-26
  • 打赏
  • 举报
回复
:) 楼主终于明白了,不变类和单例类之间是没有关系的。 随意组合,呵呵
truezerg 2004-06-26
  • 打赏
  • 举报
回复
to: jiganghao(JH)

我给你的例子是符合你的单例概念的例子。
truezerg 2004-06-26
  • 打赏
  • 举报
回复
public class MyClass {
private static MyClass ourInstance;
private String myName;

public String getMyName() {
return myName;
}

public synchronized static MyClass getInstance() {
if (ourInstance == null) {
ourInstance = new MyClass("truezerg");
}
return ourInstance;
}

private MyClass(String myName) {
this.myName = myName;
}
}

这个类是不是单例的?
这个类是不是不变的?

这个类好像看不上没什么意义,但是仔细想一下,如果 属性myName是一组系统配置参数,而且构造方法中通过读数据库来给属性赋值。因为系统只需要一个读取配置参数的类就够了,所以做成单例的。这个有意义了吧?
steven_cheng 2004-06-25
  • 打赏
  • 举报
回复
呵呵,最近忙些别的事儿,很久没来这里,没想到大家这么热情:)

我想把问题再说清楚些。在我的系统中,考虑到业务逻辑和数据访问逻辑的分离,所以应用到DAO模式。但是因为这个系统几乎不存在数据库移植的问题,所以这个DAO模式只是被我在思想上应用了一下,没有DAO工厂、也没有DAO接口,只有一个DAO的实现类,在业务逻辑上直接调用创建DAO的实例。事实上这样的DAO类更像一个工具类。至于为什么我没有把方法声明成static,因为我认为这不符合面向对象的思想,而且,这些数据访问类,是有实际逻辑概念的对象。我用不可变类的概念应该说不对,至少不严谨。仅仅是为了业务逻辑和数据访问逻辑的分离,所以没有用完整的DAO模式。因为这样的原因,才有了想把DAO做成单实例的想法。因为如果用DAO模式,我要增加DAO工厂和DAO接口两个意义不大的类,而用单实例,不用增加类。当然,我现在觉得这样的想法挺愚蠢:->
就这个问题,我比较同意ajoo(聪明的一猪),还是用DAO模式,这样DAO工厂可以隐藏实例化的细节。

To glchengang(青面),我在实际应用中就有一个单例模式的不变类:
----------------------------------------------------------------
public class ErrorInfoCache {

private static HashMap map;

private static ErrorInfoCache cache;

public static String source="";

private ErrorInfoCache() {
ErrorInfoDAO dao = ErrorInfoDAOFactry.getErrorInfoDAO();
map = dao.initErrorInfo(source);
}

/**
*
* @param source
* @return
*/
public static ErrorInfoCache newInstance() {
if(cache==null)
{
cache = new ErrorInfoCache();
}

return cache;
}

public String getCusMessage(long errorcode)
{
return getCusMessage(""+errorcode);
}

public String getCusMessage(String errorcode)
{
return ((ErrorInfoDTO)map.get(errorcode)).getCusMsg();
}

public String getContext(long errorcode)
{
return this.getContext(""+errorcode);
}

public String getContext(String errorcode)
{
return ((ErrorInfoDTO)map.get(errorcode)).getContext();
}
}
-------------------------------------------------------------
这个代码应该符合单例模式和不变类的定义。


所以,我觉得自己提的这个问题很...... :->
总结一下我现在的认识:不变类和单例模式的关系是........
他们没有关系......呵呵

学而不思则罔,思而不学则殆。我想,这才是我们这次讨论的意义。

这个贴再开一周,下周末结贴。

RamboAndGates 2004-06-24
  • 打赏
  • 举报
回复
如果,只针对楼主的问题作答的话,我觉得回答应该是肯定的。而且多线程情况,不需要同步。
可是这么做,好像没有什么好处。
myj1024 2004-06-24
  • 打赏
  • 举报
回复
To ajoo(聪明的一猪) :
这是聪明的一猪的发言:
看来我和jeff又要唱反调了。
要我说:为什么不用?

首先,这个问题本身并不是大问题。用或不用,对程序的语义都几乎没有影响。而如果你用一个static getInstance()函数封装起来,那么调用者根本无须关心。singleton与否只是那么两行代码的事。
反过来,如果你公开构造函数,那么“不使用singleton”这个决策就影响到了所有该类的使用者。换句话说,你公开了一些不应该公开的实现细节。


其次,用了有坏处吗?
我想,坏处不外乎是:需要额外写两行singleton代码。而如果使用ide的话都可以自动生成的。此处,因为是immutable的,用eager init足以,代码简单清楚。

第三,用了有好处吗?
好处自然在于效率。有人说1 byte无所谓。问题不仅仅在于内存空间,还在于给gc造成的压力。每new一次,都要调用内存分配模块,而且1 byte的东西太多更容易造成碎片。

而且,immutable object不一定是没有状态的。只不过状态不可变而已。immutable的一个重大的好处就是方便共享。要是每次使用都new,这个大好处就泡汤了。


结论:
最重要的:把是否singleton的决策藏起来。
其次,倾向使用singleton。

我的看法是:
如果一个类只有方法,没有属性,我实在看不出使用singleton有什么好处。聪明的一猪说每new一个byte,都要调用内存分配模块,而且1 byte的东西太多更容易造成碎片。既然这个类只有方法,我们大可以把它的方法都声明为static的。如果要防止用户以实例的方式来调用,我们可以把它的构造方法声明为private的,强迫以类方法的形式来调用。
jeffyan77 2004-06-24
  • 打赏
  • 举报
回复
不对,单例类可以是不变类,不变类也可以是单例的。

记得我书中有一个读取配置文件的例子就是不变的单例类。
stonecsdn 2004-06-23
  • 打赏
  • 举报
回复
呵呵,好贴
jiganghao 2004-06-23
  • 打赏
  • 举报
回复
所以不变类一定是不能做成单例模式的,也不可能做成单例模式.


truezerg(赵明宇) :如果你同意我对单例概念的定义,那么很希望你举一个既是不变类又是用了单例模式的例子出来,我会很高兴能更正自己认识上的错误. 如果你认同ajoo(聪明的一猪)单例的定义,就没必要再举例了, 我想我们的基础概念不同.
---------------------------------------------------------------------------------
many fly weight objects are both immutable and singleton. In the first version of Java compiler, one sub-optimization is: all String objects with same value share a single copy in memory.
jeffyan77 2004-06-23
  • 打赏
  • 举报
回复
不变类的定义就是其状态不变。状态是由属性实现的。

从Christopher Alexander到GOF都强调设计模式在交流和教育方面的重要性,有用的结构有无数个,但是叫做不变类的只有一种。

我觉得一方面在软件设计实践中不要拘泥于模式,另一方面讨论某一特定模式的时候,要尊重前人给出的定义。
ajoo 2004-06-22
  • 打赏
  • 举报
回复
呵呵。不争了。我对对照书本没兴趣。

不过,要是你引的书真是那么说的,那么你应该换本书了。

glchengang 2004-06-22
  • 打赏
  • 举报
回复
NilList是单例,我同意,但它是不变类吗?如果它是,那么所有单例就都是不变类了,什么是不变类??????建议你看看<<Efftive java>>这本书。

ConsList很象是不变类。但你仔佃一看,它不是噢。tl是List,List是接口,你能保证它的实现都是不变类? 好我们抛开tl属性,看看hd,它是Object,Object是值传递的,它不是不变类。 这里你没有注意不变类的另一个要点:不变类里的属性也要是不变类才行。还是建议你看看<<Efftive java>>这本书。
glchengang 2004-06-22
  • 打赏
  • 举报
回复
ajoo(聪明的一猪) ,你的给出的例子,小错误可真多,我修改正了一下,如下
interface List {
boolean isEmpty();
List cons(Object o);
List tail();
}

class NilList implements List { //可以singleton。
private static final List singleton = new NilList();

private NilList() {}

public boolean isEmpty() {
return true;
}
public List cons(Object o) {
return new ConsList(o, this);
}
public List tail() {
throw new UnsupportedOperationException();
}
public static final List instance() {
return singleton;
}
}

class ConsList implements List { //无法singleton
private final List tl;
private final Object hd;

public boolean isEmpty() {
return false;
}
public List cons(Object o) {
return new ConsList(o, this);
}
public List tail() {
return tl;
}
public ConsList(Object h, List t) {
this.hd = h;
this.tl = t;
}
}
加载更多回复(45)

50,526

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧