关于OO与关系数据库阻抗的谈论

小弟初到JDON,看了bang和道友的经典帖子感觉真的不错,看完后小弟有个疑问想请教各位:
对于我们采用OO的设计理念进行的项目开发,对于采用DDD的设计方式,我们设计出的内容是完全不考虑数据库的,最后是在仓储中进行数据访问,那么疑惑出来了,对于以前说的表示层的VO和PO如果不匹配的话,或者一个VO中关联了多个PO中的内容,这样的情况我们如何去改善。而且在设计业务模型的时候(实体),对于与实体相关联的逻辑我们应该放在实体中还是放在外面,对于采用充血方式开发的实体,对于类似HIBERNATE这样的映射框架来说可以吗?因为在用HIBERNATE的时候,很多时候仅仅是用get,set方法来定义一个实体,而且与表的关联想对应的。实际我个人认为,这些问题的根源还是因为了OO设计思想与当前关系数据库的不匹配引起的,所以导致小弟对设计实体时候的疑惑,因为以往的设计还是会采用bang所说的那种过程式开发的通病方式进行设计,希望bang以及各道友给予指点

我觉得是先有业务对象,然后需要持久的时候才有持久对象,需要传输的时候才有VO,测试领域的时候好像不需要VO和PO,VO可以根据业务对象组合或只要部分定义,跟PO没多大关系,尽管有些定义域是一致的。

但是我们最终的设计是要将持久的数据保存到数据库中,而这种保存必须要考虑到的就是数据库,前期的设计不用考虑数据库,但是在后期设计仓储的时候要考虑这个问题,并且这个时候如果发现设计的业务模型对于存储到数据库,或者对于前端显示的VO有困难或者一个VO中需要多方面的PO去关联怎么解决呢?我还是比较迷惑的,请给予解答,谢谢!

小弟是想说的,对于我们采用完全OO的思想设计系统的时候,可以抛弃以往的数据库建模,不用什么ER图之类的,而采用OO思想,利用UML用例图等等来设计业务领域模型,但是我们最终还是要将需要持久的信息存储到数据库,小弟在这个地方就产生了迷惑,如何将这些持久的业务模型转化为数据库中的表记录信息,这种转变必然是在程序中考虑的,这个时候的持久化我们应该如何去做,也会利用所谓ORM映射工具,在我用hibernate的时候都是一些贫血的PO在进行操作,这些PO按照都是存在数据库影子在里面,并不是完全的OO设计,所以这种从业务领域模型到持久化这个过渡我们应该怎么做,必须得通过SQL或者hibernate中的HQL来进行,这其中的思想请banq和道友帮解惑下,在此小弟先谢过。

hibernate auto-ddl。
另外不知您描述的是否是改造遗留系统的故事,如果这样就比较复杂点,以前弄过一个类似的,最终的协商结果是部分结构简易的数据表重建,部分数据表保留待以后调整,虽然至今也没见调整。
而另一个关于VO和PO的问题我认为应该是都和业务对象关联,它们两个并没有直接的联系。
在OO的故事里既然领域模型已经完备了,持久数据利用hibernate等工具应该比较容易。

这个问题起源于你对充血模型的误解,你以为充血模型在代码上就是一定不是表现为set/get,你看到set/get代码就认为这是贫血或失血模型,这有些盲人摸象,就象设计模式中,你指着一个类代码说我看不到设计模式,其实设计概念上模式和模型有时可能具体表现为多个类的实现,表面上贫血,实际上充血,这是符合高内聚,低耦合原则的:

充血模式=set/get类+模式(如Proxy等)+其他类

这个问题我早就在下面贴子谈过:

http://www.jdon.com/jivejdon/forum/messageList.shtml?thread=33948&count=15&start=15


[该贴被banq于2008-07-28 16:56修改过]

哦,这个我知道的,但是我迷惑一点的是,对于业务模型的GET和SET方法, 真正与业务有关的逻辑,是放在他们中呢,还是象您说的那样将这个业务实体仍然是类似于贫血模式,但是通过代理等设计模式表现为充血的呢。
如果业务实体中不光含有set和get,而且存在与领域相关的业务逻辑的话,是否对于HIBERNATE这样的ORM工具可以达到映射(我在其他论坛中看到有人说真正的充血模式在JAVA中很难实现,主要是关联这样的ORM映射工具复杂),还是采用set和get方法,但是象您说的通过设计模式达到看似贫血实际充血的效果呢?

>对于业务模型的GET和SET方法, 真正与业务有关的逻辑,是放在他们中呢,还是象您说的那样将这个业务实体仍然是类似于贫血模式,但是通过代理等设计模式表现为充血的呢。

需要自己多思考,难道OO世界有一个规定,业务逻辑必须放在Java语言的Bean的set/get方法吗?注意:设计高于语言,Beans的set/get是代表设计上的Property,也就是一种特殊的属性,难道能让业务方法压缩放入属性?除了这种向下向内压缩的思维,就不能有向上向外扩充的思维?

所以,要用好 DDD,必须有深刻的模式思维功底,有些人认为有了框架就无需学习模式,其实这是误区,模式不但在建模中需要使用,而且能够培养向上架构思维。

同时需要认清楚分析设计和语言之间的关系:Java作为一个语言平台,Domain Model作为一个分析设计概念,分析和设计之间有鸿沟,不是一一对应,只能从从分析推到设计;同样设计和语言之间也有鸿沟,只能从设计推到语言,反之就不行,不能从语言倒退还原设计的。

具体代码可见Jivejdon3案例。

btw:说什么Java不能实现丰富的Domain Model,这是片面的,我们考虑下面情况,
1.如果一个类需要多台服务器之间传输,你是将所有业务打包一个类(2M更大),形成所谓形式上的充血模型在多台服务器之间传递快?还是我只将主要实体数据和行为分离,将主要数据在多台服务器之间奔跑快呢?

2.从设计概念上讲,也不能将所有业务方法耦合到一个类中,这和过程编程有什么区别?

3.是不是有一种语言平台能够避免这个问题?我想如果有,它在现阶段就不能解决上述矛盾,除非将来带宽更宽;或者它根本不考虑性能的扩充,只考虑单机(性能上象过去Delphi一样依赖数据库能力)。


[该贴被banq于2008-07-28 18:42修改过]

多谢banq和各位指点,小弟明白了些,正如您说的,好多东西都需要去悟。感谢感谢!以后学习中有问题,还要向大家请教!

哈,刚发觉我发的帖子有点问题,刚才我说的那句
>对于业务模型的GET和SET方法, 真正与业务有关的逻辑,是放在他们中呢,还是象您说的那样将这个业务实体仍然是类似于贫血模式,但是通过代理等设计模式表现为充血的呢。
我这里说的并不是把业务逻辑放在set和get中,而是说对于业务实体有些人说只含有set和get方法叫做贫血模式,我的意思是业务实体中除了含有get和set方法,业务方法是否可以放在业务实体中,而当这种实体需要“冬眠”的时候,是否利用hibernate有一定的困难,看了banq那个连接,意思是对于业务实体的业务逻辑可以分离出来,并不一定需要把他们放在业务实体类中,而此时业务实体类仅仅含有表面的特殊属性set/get方法,而其实他们是通过set/get 加上代理等其他类共同实现的充血。这个是看后我的理解。我想问下,如果要是将业务逻辑放在了业务实体中,那这种实体的冬眠在hibernate中映射有困难吗?我们一般是采用实体中含有业务逻辑,还是分离出来业务逻辑,达到表面贫血,实际充血!谢谢!

>如果要是将业务逻辑放在了业务实体中,那这种实体的冬眠在Hibernate中映射有困难吗?
看看我前面帖子后面部分,从设计上讲这是不对的,这是紧耦合;另外,一个20M的业务实体要进行分布式计算,必须进行序列化,多增加负担,同样冬眠到数据库是不是也很耗费性能(其中也涉及序列化或动态加载)?

注:Hibernate只要配上一个分布式缓存就能实现分布式。
[该贴被banq于2008-07-28 20:31修改过]
[该贴被banq于2008-07-29 09:16修改过]

业务逻辑放在实体中是可以非常容易的应用hibernate持久化的,但是不宜采用。是不是以前管这个叫有血?
另外网络瓶颈对soa影响也很重大吧。什么时候才有高速网络,至少看电影啥的也方便。

想问下对于不建议将业务逻辑写在实体中,如果采用分离,我们应该以怎样的设计思路进行分离,能否指点一二,banq和各位道友的思路真的想好好学习借鉴下。请详细说明下,谢谢了!

我觉得是先有业务对象,然后需要持久的时候才有持久对象,需要传输的时候才有VO,测试领域的时候好像不需要VO和PO,VO可以根据业务对象组合或只要部分定义,跟PO没多大关系,尽管有些定义域是一致的。

--vo不应该是传输时有的吧,按字面上来看它应该属于值对像,传输的应该是DTO吧。VO应该是某个模型的子集,我这么理解!