状态模式和hibernate问题请教

不知道大家在使用状态模式和hibernate这种orm工具时有没有遇到这种问题:
比如有Context,State1,State2这几个类,在我的设计里,State1和State2是值对象,而且继承接口State.在Context里有对State的引用。State接口的几个方法接受Context参数。每个具体的State实现有一个类变量code.
数据库表设计为一个表,有一个字段存储整形数字表示状态。此时我想把状态对象的类变量映射到这个字段。但是实在找不到好方法。大家帮我看看,是我的思路有问题还是hibernate不能满足这种需要?(不想修改数据库表结构,也不想将状态对象由值对象变为实体对象)

只要你抓住对象,Hibernate是最好使用了。Hibernat中文是冬眠,意识就是对象的冬眠(持久化)。

你可以将你每个状态之类直接冬眠,或者,将state1和state2等值对象和其关联的实体一起冬眠持久化(通过Hibernate关联配置)。后者符合DDD,推荐使用。

banq大哥,我理解 你的意思,我现在是在实现的时候遇到了问题。
不知道我理解的是否正确:在Hibernate里,如果一个类对应了一个map文件,是否说明这个类是一个实体对象?因为我这个状态模式里的状态对象,我认为是值对象,应该用Component映射,但是component这种映射好像并不支持继承映射,这就是我的问题,还请banq大哥指教

>如果一个类对应了一个map文件,是否说明这个类是一个实体对象
正好相反,只有确定一个类是实体对象,才配置一个map文件。

那么如果确定一个类是实体对象呢?,这就是系统分析建模了,在Evans DDD中有这样定义,比如最近讨论的广交会网站分析案例大部分就是确定哪些实体类。
http://www.jdon.com/article/33006.html

比如:订单和订单状态就是这样的关系,订单状态作为实体订单的值对象,是和订单这个实体一起冬眠的。

以下是有感而发,不针对楼主:
Hibernate只是架构技术,属于计算机软件技术,计算机软件技术是为客观需求服务的,我们技术人员千万不能在软件技术领域打转转,忽视需求,导致因果关系倒置,看不清本质,陷入猫追尾巴的圈子,所以,领域建模才是技术软件人员必须掌握的基础知识,虽不一定进行系统分析,但是可以开拓眼界,对技术能够迅速抓住本质。
[该贴被banq于2007-12-04 13:01修改过]

banq大哥,是这样的,我在进行需求分析和设计的时候,的确没有想过实现细节的东西,所以运用了状态模式.
因为这个系统既是我设计,也是我实现的.在具体编码阶段,我想把Context和它的状态实例持久,然后以后再从持久的地方取回来.而且我也是刚开始用Hibernate,还不太熟,因此在Context的map文件里,我把这个State类用Hibernate的Component映射,这样持久没有问题,但是将来从持久层再把它取回来时,这个状态对象应该时状态类的某个具体子类的实例,但是Component又没有配置subclass的地方(还是有类似的功能?我查了dtd,没发现subclass),因此Hibernate再加载的时候又怎么能知道生成哪个具体子类的实例呢?

>Context和它的状态实例持久

状态不能单独存在,状态肯定要属于某个实体,状态是一个从属特点,一定要有主人,你不能单独将状态持久化,那么这和传统过程语言直接将某个整数变量值用SQL保存数据库有什么区别?

你的Context就应该是一个实体,状态是它的值对象,他们之间的关系是组合关系。就像Order和OrderState关系一样。如果你的Context不能用实体表达,也就是不是一个类似订单Order这样实体,那么你必须重新分析建模。

一旦找出状态的实体主人,那么实体和值对象之间就是一个自然组合,然后你才可以考虑用Hibernate的1:1关联或Component来映射。映射配置必须根据实体和状态之间的关系设计来配置,Hbernate配置属于OO设计后的具体实现细节。如果没有OO设计,谈论后面Hibernate配置等具体细节就没有意义。就象如果你出发方向都没有确定,就迈步开始走路,岂不是没有意义?

你这个案例就是典型的领域建模DDD加状态模式,状态模式要完全对象化使用,必须有DDD和Hibernate等O/R mapping框架系列技术支持。


[该贴被banq于2007-12-06 09:09修改过]

banq请看我的这张图:

上面这个图符合banq大哥的意思吧。但是我在持久Context对象的时候,map文件应该这样写吧:


<hibernate-mapping>
<class
name="com.sinosoft.domain.beans.sipo.Context"
table="SU_EXAMINER_MANAGE"

>
<id
name="id"
column="USERID"
type="string"
>
<generator class="assigned">

</generator>
</id>

<component
name="state"
class="com.sinosoft.domain.beans.State"
>
</component>

</class>

</hibernate-mapping>

我还应该在component下面增加subclass元素吧,但是dtd规定component没有subclass这个element
我想达到这个目的:


<subclass name="com.sinosoft.domain.beans.sipo.ContextStateNew" discriminator-value="1">
</subclass>
<subclass name="com.sinosoft.domain.beans.sipo.ContextStateValid" discriminator-value="0">
</subclass>


[该贴被power1128于2007-12-06 16:24修改过]


Hibernate中Component只是一些属性的包装,不能再子类化了,因为已经是最底层(类的属性比类还低):
http://forum.hibernate.org/viewtopic.php?t=929436&highlight=component+discriminator

所以,如果使用Hibernate,那么就直接使用1:1关联+ subclass的方法,不要认为Hibernate的实体一定与我们设计概念的实体是一一对应的,给予了一个主键id就变成设计概念上的实体了,因为Hibernate实现在设计后面,不可能改变之前设计概念,这种一点不协调只能说明对象和关系数据库的不匹配天然矛盾决定的,就象把黑与白放在一起,总是有分界线这样缺点,不可能平滑,除非你用对象数据库。

如果一定要使用Component,那就在状态类中自己对这些类的变量进行赋值,比如StateNew的内部值为1 StateValid内部值为2,然后,将这些值通过Component保存在ContextState之中,意思和subclass差不多,subclass好处就是将某个具体子状态对应相应的值进行XML配置了。

其实,上面这些回答我也被你绕进去了,因为Hibernate细节实现不能决定我们模型的设计,通常我们是采取第二种方式,这样,就不依赖具体框架,无论它是Hibernate或对象数据库,所以,在进行设计时,建议不要将具体框架的设计细节混淆到我们的状态模式设计等高层次上。


[该贴被banq于2007-12-07 12:18修改过]

首先非常感谢banq大哥热心解答.我也看了您给我的链接.不过说实在的,我还是没弄 明白我该怎么弄.
首先您看我画的那个类图没有问题吧,Context是Entity,CheckState是ValueObject(这里不用Component这个名词).这应该是符合状态模式的定义的吧.如果上面的设计没有问题的话,我现在要持久Context对象,具体应该怎么做?

我想我明白您的意思了:
>如果使用Hibernate,那么就直接使用1:1关联+ subclass的方法,不要认为Hibernate的实体一定与我们设计概念的实体是一一对应的.
也就是说在Hibernate里映射了Id的,或者在类里定义了id的,不一定就是Entity,Entity和ValueObject应该从设计上来区分,具体实现的时候,就象您说的:
>这种一点不协调只能说明对象和关系数据库的不匹配天然矛盾决定的,就象把黑与白放在一起,总是有分界线这样缺点,不可能平滑,除非你用对象数据库
[该贴被power1128于2007-12-10 12:18修改过]

yes u got it

我对值对象和状态对象好生疑惑!既然是状态还有必要持久化吗?好像jivejdon中的forumstate和threadstate都是在工厂中动态创建的,还有值对象和状态对象有什么区别呀,状态对象一定是值对象吗?值对象一定和它关联的实体拥有相同的生命周期吗?还有值对象和状态对象在对象关系中是聚合呢?还是组成?
本人菜鸟一个,望高手指教!
[该贴被oojdon于2007-12-14 16:26修改过]

看看孙卫琴写的那本hibernate的书吧,里面有一章讲关于继承关系的映射的,看了就明白了。

楼上的误解了,我问的是值对象和状态对象问题,而不是继承映射!