论坛首页 Java版 Hibernate

继承的尴尬,我该如何避免?

浏览 5662 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2008-07-17

来看一个很简单的场景,比如说有一个实体叫做计划。计划分为已执行的,和未完成的(貌视马丁大叔的分析模式第8章也有这样的概念)。在此我想到了继承,图如下:



为了简便起见,我使用了Hibernate中叫做table per class hierarchy的方案来实现,那么自然对应的数据库当中,我使用了一张表,结构如下:

 
                   

 

体系中的继承类都用一个表保存,通过一个字段(discriminator column)的值进行区分。计划表对应的PO配置文件如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
	<class name="Planning" table="PLANNING">
		<id name="planId" type="java.lang.Integer" column="PLAN_ID">
			<generator class="sequence">
				<param name="sequence">SEQ_PLANNING</param>
			</generator>
		</id>
		<discriminator column="STATE" type="java.lang.String" />
		<property name="planContent" type="java.lang.String" column="PLAN_CONTENT" length="1000"></property>
		<property name="startTime" type="java.sql.Timestamp" column="START_TIME" length="7"></property>
		<property name="endTime" type="java.sql.Timestamp" column="END_TIME" length="7"></property>
		<property name="createTime" type="java.sql.Timestamp" column="CREATE_TIME" length="7"></property>

		<subclass name="ProposedPlan" discriminator-value="2">
			<property name="currentProgress" type="java.lang.String" column="CURRENT_PROGRESS" length="22"></property>
		</subclass>
		<subclass name="CompletedPlan" discriminator-value="1">
			<property name="planResult" type="java.lang.String" column="PLAN_RESULT" length="22"></property>
		</subclass>
	</class>
</hibernate-mapping> 

 
针对单独的已执行和未完成计划操作,都没有问题,一切顺利。但是接下来问题来了,在需要把未完成变成已完成的时候,我一下陷入了麻烦了,
在继承的关系下,我如何来实现子类之间状态的互相转变?

  • Da550862-5ef2-3c7c-9198-09d23bce2212-thumb
  • 描述: 继承
  • 大小: 11.6 KB
  • 1a9a490f-91c4-3c4b-9951-c0bcd9a36d3d-thumb
  • 描述: 表
  • 大小: 8.6 KB
   
时间:2008-07-17
很明显,这个问题不应该通过继承来解决。这只是一个状态的问题,应该是增加状态字段。而不是每一个状态都会凝固成一个类型。
   
5 请登录后投票
时间:2008-07-17
未执行计划和已执行计划,存在一个先后过渡的联系。
一般情况下,我们设计一个类,这个类的本质是相对持久的,比如Person->Teatcher,Person->Student,如果说一个Student要过渡到Teacher,OO设计可以不去考虑,让这个Student注销,然后注册一个Teacher就行了。
未执行计划和已执行计划可以合并为一个类,通过属性设置来进行过渡。至于数据表,根据需要,设计成一个表或者两个表都可以。
或者,如果有足够理由需要设计成两个类(比如两个类中有不同的方法),那就可以考虑Student-〉Teacher的这种情况,由程序来自动完成:
Student student = StudentService.find("theStudentGoingtoBeTeacher");
StudentSerivce.remove(student);
Teacher teacher = new Teacher();
TeacherService.add(teacher);
   
0 请登录后投票
时间:2008-07-17
拿着锤子 看什么都是钉子
楼主中了模式的毒
   
0 请登录后投票
时间:2008-07-17
谢谢canonical,sunsong 的回复,不通过继承,只考虑状态的问题,确实是很简单的就处理了。
我对hibernate的继承的把控不到位,如果是实际项目,我肯定也是那样处理。

sunsong的第二种方式可以满足一定的效果,但是这样做有一点:实体的ID变了。换句话说,确实少了
一个Student多了一个Teacher,但是Person已经不是这个Person了。
xly_971223 拿着锤子 看什么都是钉子,楼主中了模式的毒 这句话在此处对我没有帮助。
上面是我举的一个例子,也许不恰当,但是我相信在继承当中子类之间的角色是存在互相转变的场合的。
就继承而言,是关系数据库与面向对象冲突的最激烈的地方,我在此讨论hibernate继承的真正目的是想知道它提供的继承关系在我们实际使用的频率到底有多高?
就我本身的使用而言,我很少用到它,甚至是刻意回避它,我没有这方面的使用经验,所以我希望大家能分享一点经验,对我对其他使用者都有好处。
别最后的结果是,继承关系我hibernate提供了,这表明我符合JAVA习惯了,但其实大家都不用!
这样对大家都没有什么帮助。
   
0 请登录后投票
时间:2008-07-17
楼主举的这个例子实在是不太适合用继承来处理,使用一个表示状态的属性就可以了。请举个实际的需要在运行过程中改变身份的例子,大家再分析一下
   
0 请登录后投票
时间:2008-07-17
想不通为什么马丁大叔为什么要提出一个这样的例子呢? 上下文是什么?
   
0 请登录后投票
时间:2008-07-18
楼主连业务主键和逻辑主键都分不清。
   
0 请登录后投票
时间:2008-07-18
这个最好是用状态模式, 因为有一个状态转换的过程(这个过程也可能带有一些复杂的业务逻辑)。
   
0 请登录后投票
时间:2008-07-18
这个最好是用状态模式, 因为有一个状态转换的过程(这个过程也可能带有一些复杂的业务逻辑)。
   
0 请登录后投票
论坛首页 Java版 Hibernate

跳转论坛:
JavaEye推荐