思路话语

。Arlen:思想有多远你就能走多远...

Enterprise Persistence Design

(本文引自:http://idior.cnblogs.com/articles/195193.html)
Introduction

本文将介绍以下内容:

1.       企业应用中的持久层设计

2.       Transparent Persistence的意义

3.       Hibernate给我们带来了什么

4.       Domain Model Design

5.       Spring又能做些什么

     本文涉及的内容如此之多, 以致于不可能在每一点上都讲的很细, 可以说本文的特点在于大方向的把握, 带你从宏观的角度对企业应用中的持久层有所认识, 随后的应用及研究都需要个人花费大量的时间和精力, 当然我会在以后就一些细节问题在发表文章, 同时也希望更多的bloggers以此入手, 谈谈你的心得和体会.

阅读本文前, 如果你缺乏O/R Mapping的了解,建议参考O/R Mapping 基本概念.

History

个人对面向对象以及模式比较感兴趣, 也算是坚实支持者之一.长期以来也写了不少有关面向对象和设计模式的文章, 不过由于无法用于实践一直心存疑惑, 特别是在有数据库应用的场合下更是不知如何摆脱关系型数据对于面向对象的束缚. 另人失望的是, .Net社区从未见过类似文章让我得窥其貌. 既然不能寄望于人,只能自己潜心研究,希望能有所领悟. 这两周一直在查看相关书籍, 终有所心得, 特写下此文, 望与大家互相探讨, 互相学习. 

对于企业应用最成熟的领域自然是J2EE.尤以EJB为代表,下面就从它谈起.

EJB中负责persistence的是Entity Bean. Entity Bean就相当于一个Active Record,它自身就包含了Save, Load方法,也就是persistence logic.从职责分配的角度来看,你已经会觉得不太合理.如果利用BMP来实现persistence你还需要自己去实现相关的persistence logic, CMP虽然由于容器的支持,使得 persistence的实现不再需要用户太费神,但是不管怎么说persistence logic还是包含在Entity之中了. 问题还不仅如此,如何从数据库中找到你所需对象?你要实现EntityHome接口来完成查找的功能,看看吧Entity做了多少的事?

Entity Bean做了这么多的事, 似乎是劳苦功高应该能完成自己的任务了,不过Entity Bean可真是吃力不讨好? 为什么呢? 他把自己该做的事忘了. Entity在很多时候成为了一个只有数据没有行为的"哑对象", 那么行为也就是业务逻辑哪去了?它们往往被放到XXXEntityManager中去了.


                                  

这样的模型带来了什么问题?

1.                       它破坏了面向对象的封装的特性, 在这样的模型下, Entity必然要把它所有的属性暴露出来.

2.                        既然Entity没有行为,必然无法利用到多态的特性, 那么在XXXEntityManager中一旦涉及区分Entity类型的逻辑, 就会出现很多if else语句,繁琐不说,也不利于扩展,维护.

既然封装,多态都没了, 那也就不存在面向对象了. 所谓的类也就成为了一些个数据和函数的包装体,是彻彻底底的结构化模型在面向对象中的复辟. Martin 给它起了一个名字,Transaction Script.

既然XXXEntityManager的任务就是围绕XXXEntity的数据做操作为什么不直接让XXXEntity自己做?

Entity不是不想做, 问题就在于此时此刻它多了一份责任, 它要负责自身的persistence , 试想一下如果Entity中存在业务逻辑, 那么在逻辑中必然会频繁的更改其自身的属性.而为了使得这些更改能体现到数据库中.那么所有的业务逻辑中就经常需要显式(explicit)Save, Update. 在这种情况下, 这样包含persistence logic的业务逻辑一旦脱离了EJB容器,根本无法测试.

由此我们发现Entity Bean做了很多不该做的事情, 同时该做的事情它却没有做.由此在责任分配的原则下,分以下三点讨论:

  • 1.     不该做的不做.                              Separate persistence from business
  • 2.     该做的要做.                                  Implement business
  • 3.     自己独力不能做的交给别人做.  Delegate, Façade

 

Main Content

1.     不该做的不做.

DAO模式提供了某种程度的persistence logic的分离, 但是上面提到的问题在DAO模式下是否得到了解决呢? 没有! 传统的DAO存在和EJB同样的问题, 它比Entity Bean好的地方在于利用strategy模式将DAOEntity Bean中抽象出来,由专门的类来实现DAO. 因为Entity Bean只包含了DAO的接口.这样使得面对各种不同的数据源时能够不破坏Entity Bean的内部实现. 

 

上面两种模型都没有解决业务逻辑和persistence logic分离的目的.

由此可见,要避免上述的问题必须将业务逻辑和persistence logic完全的分离.为什么我们早没有这么做? Technical Knock Out. 当时的技术达不到.要想实现完全的分离, 我们需要一种透明的persistence 机制.

何谓透明?

让我们再来看看之前的问题:

如果Entity中存在业务逻辑, 那么在逻辑中必然会频繁的更改其自身的属性.而为了使得这些更改能体现到数据库中.那么所有的业务逻辑中就经常需要显式(explicit)Save,Update.

其实问题就在于避免在业务逻辑中,显式的采取有关persistence的操作.我们需要一种机制------它能够在完成一个业务逻辑后自动的检测到对象状态所发生的变化.随后在事务提交时,将发生的变化保存到数据库中.这里突然出现了事务的概念,别急在后面还会有解释.如果有了这么一种机制, 我们就应该可以实现业务逻辑和persistence logic完全分离.

谁提供了这么一种transparent persistence的机制? Hibernate!

Hibernate的支持下,persistence 并不由Entity自己负责. Hibernate会监视对象的变化.所有的更新只要在事务提交的时候就会保存到数据库中, 不需要在业务逻辑中显式得去一次次调用DAO中得方法来完成数据库同步得目的, 也就是实现了业务逻辑和persistence logic的完全分离.并且Hibernate还支持级连(Cascade)操作,这使得在你的模型设计良好的情况下,save,update的操作最少. 当然由于Hibernate的引入, 现在的DAO需要重新设计了.

先来看看以往DAO所支持的操作. Save() Update() Load() 这三个是最起码的. 现在呢? 你可以去掉Update(). 很奇怪吗? 前面已经提到了, Hibernate可以自动检测到对象状态的改变,并且在事务提交的时候存入数据库. 也就是说Update这个操作其实可以交由事务来完成了. 何时实现事务呢? 别急还在后面.

                           
Tip这里我们将EntityDAO分开了, 不过在后面我们还会将它们再合起来.那个合并的地方就是进行事务处理的地方.


     
 真的可以去掉Update()吗? 未必! 有些对Hibernate有点了解但有了解不深的人可能现在会奇怪为什么在Hibernate中还要提供Update()这个方法(属于Session对象). 还有人会奇怪为什么还有一个SaveUpdate()方法. 需要注意在前面一再强调在同一个Session并使用事务的情况下, 当对象状态改变时是不需要调用session.Update(xxxEntity)的完成更新数据库操作的. Update以及SaveUpdate方法是用于上层(maybe UI Layer)的操作的, 也就是离开了当前的session的Detached Object.当你需要Reassociate Detached Object时就会用到Update, 以及SaveUpdate方法. 所以当你想用Detached Object取代DTO的时候(这个思想受到不少专家的欢迎,当然这也有一个Balance的问题), 你需要在DAO中提供Update()的方法.      

                        
Note如果你现在不明白session以及 Detached Object, 而又对本文的内容感兴趣的话,希望你自己去查阅相关资料.毕竟篇幅有限,不可能面面俱到.

 

 

  是不是这段看的有点晕? 确实这段是需要一些有关Hibernate的基础的.不过它并不影响你理解本文的主要思想.可以把它略过.当你需要深入研究的时候再去看相关内容. 之所以提到它, 是想把Hibernate介绍的更深入一些, 或许对某些人是有益的.

现在总结一下Hibernate给我们带来的好处.

1.       Transparent persistence自动检测变化,以致DAO可以和Entity完全分离.某些时候DAO可以不必实现update的方法.

2.       级联操作使得save语句可以减到最少.

3.       Detached Object可以在某些情况下使得DTO消失.(DTO是一个经常让人比较心烦的东西)

4.       Hibernate提供了实现细粒度(fine-grained)的对象的方便机制.

5.       Hibernate提供了Lazy-Load的支持.

         
Hint实现Transparent persistence我认为是Hibernate最为成功的地方之一, 也是高层的O/R M应该起到的作用.动态生成SQL语句只是实现这一目的的手段之一, 不要把它作为O/R M的实质.
 

             *4. 5. 在本文中并没有提到, 不过作为掌握Hibernate必须了解的内容,我还是在此列出.

 

2.     该做的要做.

既然利用Hibernate提供的Transparent Persistence,我们实现了将Persistence LogicBusiness Logic中分离. 这样我们就可以在Entity中编写相关的业务逻辑.此时我们把这个Entity称之为Domain Object. 封装多态的特性可以在Domain Object中得到很好的体现.

现在我们已经确定将在Domain Object中包含Business Logic, 随之而来有下面几个问题:

1.                       Domain Object中的Business Logic的性质是否都一样?

2.                       是不是所有的Business Logic都由Domain Object来完成? 哪些Business Logic不是由Domain Object完成的?是否还需要Service, Manager?

前面我们一直强调在Business Logic中经常会改变对象的属性,从而混杂有Persistence Logic. 但是有些Business Logic并不改变对象的属性, 它们只是读取属性,以完成一些工作.一个很常见的例子就是计算工资.在这种Business Logic中本来就不涉及到Persistence Logic, 它也无需Hibernate监视对象的状态改变, 无需事务的包装.我们应该把这种Business Logic和改变对象状态的Business Logic区分开来.

 

 

        
HintPersistence的角度Business Logic的分类:
1.                 涉及属性改动,需要反映到Persistence LayerBusiness Logic (需要Façade的事务包装)
2.                
仅仅读取相关属性, 没有需要反映到持久层的Business Logic

如果所有的需求,只需要一个个独立的对象来完成, 那么可能仅仅依靠Domain Object我们就可以完成任务. 但是很多情况下, 有些任务需要很多没有关联(Association)的对象之间进行协作才能完成. 这个时候光依靠Domain Object是无法完成任务,如果要靠你说靠谁(这里也说明如果你能组织好Domain Object的关系是有可能仅仅依靠它就搞定的,但是有的时候很难避免这种情况), 所以就需要一个上层来组织它们. 这个上层的作用非常类似于J2EE中的Session Bean.从事过J2EE开发的人都知道,J2EE中是不鼓励Entity BeanEntity Bean直接关联. 因此这个关联协作的工作就交给了Session Bean. 这里也是同样的道理. 我们需要一个Service, 一个Façade.


        需要注意的是: 不是说所有关于多个对象的业务逻辑都要放到Façade中去实现, Domain Object中的业务逻辑同样可能由多个对象协作完成.只不过这里的多个对象是Domain Object的属性.它们之间存在明显的关联(Association)关系.可以通过对象之间的关联定位到,而不需要使用到DAO来查找某个对象. 正因为这点,不要因为Hibernate提供了HQL,我们就到处用它, 一来在Domain Object中不应该使用有关DAO的操作, 二来在Domain Model中提倡的是通过关联定位对象,而不是频繁的查找.HQL的用途不应该被曲解.HQL应该更多的用在报表等等批量数据输出的地方.(不过这里是DataSet的强项)

                   
HintDomain Object角度对Business Logic的分类:
1.       由一个根(Root)Domain Object通过直接的属性关联实现的Business Logic
2.       由多个独立的Domain Object通过Façade联系起来一起完成的Business Logic
 

        3.
自己独力不能做的交给别人做 

         
 

 

别人就是上面所提到的Façade. 上文提到了仅仅依靠Domain Object, 有些业务逻辑将不太方便实现,所以引出了Façade的概念.让我们来看看Façade具体做的哪些事:

1.         实现需要多个没有直接关联的Domail Object协作的Business Logic (CooperatorOperation)

2.         对涉及更新数据库的业务逻辑进行事务的包装. (PlaceOrder)

3.         DAO中的Persistence Logic提供包装. (Update)

4.         Domain Object(Business Logic)DAO(Persistence Logic)被分开后再次组合,组合的目的是为了1.

在引入Façade, 暴露给上层的是不是只有Façade? 我个人觉得未必, 我的想法是将FaçadeDomain Object都暴露给上层,DAO隐藏起来. 由于Hibernate 具有Reassociate Detached Object的功能.此时的Domain Object在适当的情况下可以充当DTO的作用.

基于这样的考虑,让我们来看看Façade应该如何封装它下面的Domain ObjectDAO.

因为Hibernate虽然有自动检测变化的能力, 但最终需要通过事务的提交才能将变化真正的反映至数据库中. 既然事务的包装的任务放在了Facade这里解决,那么一切有关对象状态变化需要反映到数据库中的业务逻辑都需要经过Façade的包装. 这里面包括了Domain Object中的业务逻辑(PlaceOrder)Façade中多个Domain Object合作的业务逻辑(CooperatorOperation).只要它们涉及Persistence,就需要在Façade做事务包装. 当然只读的业务逻辑可以不必包装.

这样包装后, 上层接触到将是Domain Object的只读业务逻辑, Façade的所有业务逻辑以及经过Façade包装后的DAO中的Persistence Logic. 需要注意Façade绝不只一个.         All Done!

Conclude

      以上模型有什么优点?

        
        注意Domain Layer那部分,你会发现这里你不需要关心任何其他的事情, 你所需要关心的就是业务逻辑. 这是最让我觉得心动的地方. 同时你会注意到Domain Layer和Persistence Layer没有任何的联系,这样大大提高了业务逻辑的可测性. 并且如果你设计良好,组织好类与类之间的关系,Domain Object将承担起主要的责任, Façade尽量只做一层简单的包装. 这样我们就可以关注于领域模型, 还较少的考虑其他技术方面的细节.

       目前的不足主要集中在FaçadeDAO这里,这里需要考虑很多技术上的细节.Facade与一些对象关联,产生的依赖关系可以设计成动态注入, 事务的编写很费事, 数据库连接的打开和关闭等等麻烦的事.

And More

What About Spring?

由于FaçadeDAO有明显的依赖关系,依赖注入的任务可以依靠SpringIoC框架. Hibernate异常的处理支持不够通用,.Spring提供了一套通用的异常处理模板,还有支持数据库连接关闭等一些方便Hibernate使用的模板.Spring还对事务的处理提供了强大的配置功能, 避免了很多不必要的代码,维护起来也很简单.                

                             

HintSpring 对Persistence Layer的支持
1.           Dependency Inject
2.           Generic data access exceptions
3.           A clean model for transactions
4.           Consistent template support for Hibernate and others



写在最后的话

 

这篇文档的缺点在于没有实例的支持,显得过于理想化,过于理论化. 所以希望在以后能开发一个示例,(没有实例的支持也是我的遗憾,毕竟一个涉及面如此之广的例子不是那么容易设计和实现出来的) 也好对其中涉及的技术细节做进一步的解释. 不过理想化,理论化的东西也不是完全没有意义, 它可以起到更好的指导作用, 让我们在实施的时候尽量往较好的方向努力, 也即更加明确目标. 还有本文涉及内容实在太多, 有待以后文章不断就某些专题进行补充.

至于本模型的适用范围, 以及OO的好坏, 这些个人都有自己的见解. 可能你觉得本文对你毫无价值, 那也是正常之事, 只是我更希望在评论中更多的针对主题(领域模型).而不要发散的太广.

关于.Net的平台下表现层(UI Layer)的设计, 以及如何和当前的持久层(Persistence Layer)相结合, 是本人的尚未了解的领域, 希望听到你的声音.

以上有关Hibernate的介绍同样大多适用于.Net下的NHibernate, 但是Spring.NetSpring差的还比较远, 比如对事务的支持, NHibernate的支持都没有. 不过.Net下的Castle项目组倒是对事务和NHibernate的有所支持.希望有人能给予指引性的介绍. (绿叶?)

      

 

参考资料:   

<<Expert One on one J2EE Development Without EJB>>

<<Patterns of Enterprise Application Architect>>

<<Core J2EE Patterns>>

<<Domain-Driven Design>>

<<Hibernate in Action>>

另外javaeye论坛中的一些观点也是参考和借鉴的资料, 尤其是Robbin兄的一些见解.

All these resources are Highly Recommended

Feedback

# re: Enterprise Persistence Design  回复   

2005-07-18 16:47 by happyprogram
好文,慢慢消化。。。

# re: Enterprise Persistence Design  回复   

2005-07-18 17:56 by THIN
idior是不错的Bloger,值得大家学习

# re: Enterprise Persistence Design  回复   

2005-07-18 18:19 by 冰火
不错,娓娓到来,我就没有你这样的才华啊。

对于文中的观点可能和你的理解有些出入。

首先,对于Service的使用有疑问!

我觉得Service不是必要的。我是说Service layer。

Domain model并不仅仅是包含属性和方法的类(Domain entity class),还包含一些起控制作用的类(Domain control class)

这些控制类完全可以起到Service layer中相关类的作用,并不一定非得把它们组织到单独的Service layer层中去。

文中你推荐将Service layer和Domain layer都暴露给UI我也有异议。

我觉得既然提出了Service layer那么完全可以隔离Domain layer了。

每个Service 类通常是一个应用控制器类或者是用例控制器类。

隔离的好处是能够给用户提供了一个统一的视图或接口。

当然这些都不是绝对的。

其他的我慢慢看,想好了再交流。

# re: Enterprise Persistence Design  回复   

2005-07-18 18:25 by 冰火
文中,你对Business logic的划分方法我也是不赞同的。

Domain object 完全可以包含查询动作。比如某些domain control class类中。不是只能操作直接关联的对象。

# re: Enterprise Persistence Design  回复   

2005-07-18 19:23 by shanyou
我的网站上的一篇文章,Castle实践http://www.keyusoft.cn/Contentview.aspx?year=2005&month=$7&day=$16&postid=72,内容很多是博客园叶子的家的系列文章的整理。我的网站所使用的就是你本文所述的内容的dotnet的版本。

# re: Enterprise Persistence Design  回复   

2005-07-18 20:54 by idior
@shanyou
你是说你建设网站的持久层设计和我的思路很像?

◎冰火
仔细考虑下你的Domain Object中是否含有persister Logic
---
隔离的好处是能够给用户提供了一个统一的视图或接口。

当然这些都不是绝对的。
---
暴露domain object其实是基于代替DTO的考虑,Hibernate的作者也提到使用PO(Persistence Object)来代替DTO。 不过这方面我也不是太确定, 因为涉及ui Layer

# re: Enterprise Persistence Design  回复   

2005-07-18 21:23 by 冰火
我明白你的Facade是怎样的,提取Service layer也是一种可选的方案。我是说不是必要的。而且通常我不会用单独的Service layer。

服务层主要的目的是为客户提供统一应用接口,协调响应(如事务)。并剥离应用逻辑。将原本的领域逻辑分为两类:应用逻辑和领域逻辑。

这样更加便于领域逻辑的重用,以及应用逻辑的变更。

特别是在工作流类似的系统中好处更明显。

但一般的系统用处就不大了,Martin Flower是这么认为的,我同意这种看法。

当然在这一点是有争议的。

# re: Enterprise Persistence Design  回复   

2005-07-18 21:26 by 冰火
另外,为什么你会认为我所说的domain object包含了persiter logic呢?

# re: Enterprise Persistence Design  回复   

2005-07-18 21:30 by 冰火
@idior
暴露domain object其实是基于DTO的考虑?

用到DTO才不应该把Domain object暴露给UI。

如果你不用DTO,直接把PO传递到UI当然也是可选的方式。

当用到DTO时通常会用远程外观来封装。

# re: Enterprise Persistence Design  回复   

2005-07-18 21:47 by 冰火
@idior
如果你没有Service layer那么你的查询,更新等持久化操作通过什么来调用呢,当然是Domain layer了。

其实数据访问也只是一种服务,就像io一样,为什么domain layer不能调用他们呢。domain object本身就有持久化的概念在里面,你是不能把它剥离的。

只是对数据访问的细节我们通常是封装在Data Source layer里的。

然后运用依赖倒置,我们得到这样的两种方式(我觉得1简洁多了):
1、DomainModel<->DaoInterface<-DaoImplement->Database
DomainModel<-DaoImplement

2、ServiceInferface<-Service->DomainModel<->DaoInterface<-DaoImplement->Database
DomainModel<-DaoImplement

# re: Enterprise Persistence Design  回复   

2005-07-18 22:01 by idior
@冰火
恐怕你还是没有体会"不该做的不做."中我的想法.
其实简而言之就是让Domian Layer更加纯净, 不涉及业务之外的问题.
当然这时理想化的东西, 实际操作起来又是一回事, 我只是提出这个想法, 这也是本文的核心思想.

---
既然XXXEntityManager的任务就是围绕XXXEntity的数据做操作为什么不直接让XXXEntity自己做?

Entity不是不想做, 问题就在于此时此刻它多了一份责任, 它要负责自身的persistence , 试想一下如果Entity中存在业务逻辑, 那么在逻辑中必然会频繁的更改其自身的属性.而为了使得这些更改能体现到数据库中.那么所有的业务逻辑中就经常需要显式(explicit)的Save, Update. 在这种情况下, 这样包含persistence logic的业务逻辑一旦脱离了EJB容器,根本无法测试.
---
接口依赖是一种弱依赖, 但总没有不依赖干净.而Hibernate这样的orm提供这么一种可能.你注意一下有关Transparent persistence的内容.

# re: Enterprise Persistence Design  回复   

2005-07-18 22:09 by 冰火
@idior
不该做的不做,我当然同意拉。

我是不认同你说的在Domain layer里不能调用数据访问的观点。我认为这是该做的。

---
这样包含persistence logic的业务逻辑一旦脱离了EJB容器,根本无法测试
---
你这是对EJB的观点,我是同意的。

EJB2.x特别是实体Bean并不是非常成功的设计,否则,EJB3也不会大改了。

# re: Enterprise Persistence Design  回复   

2005-07-18 22:23 by idior
我的思想是专注于业务逻辑. 不考虑和业务无关的事.
你可以保持你的想法(也是很现实的想法,如果我真正开发的时候也许也是这么做), 让我们听听更多的意见吧. :)

# re: Enterprise Persistence Design  回复   

2005-07-18 22:51 by 冰火
@idior
你所描述的透明,我是认真看过的。

我所说的难道不能做到透明?

我觉得你可能误解我得意思了。或者我开始表达的不清楚。

我们的分歧主要是:

1、你认为Service layer是必要的,或者你认为要做到Transparent persistence的话就Service layer是必要的。
我认为是不必要的,即使是要做到Transparent persistence。

2、因为你用到了Service layer,所以你的数据访问调用代码都放到Service里去了。Domain layer则不需要数据访问调用了。
而我当在没有用到Service layer时,我得数据访问调用代码是放到domain layer中的,比如在domain control class中。

你仔细想想,用Service layer和不用Service layer对Transparent persistence有影响吗?其实是没有影响的。

用Service layer和不用在数据访问方面是没有本质的区别的。

用不用Service layer关键不在这里,我开始已经详细说明用Service layer的好处了。

# re: Enterprise Persistence Design  回复   

2005-07-18 22:55 by 冰火
当然,每个人有不同的想法是很正常的。呵呵

# re: Enterprise Persistence Design  回复   

2005-07-19 10:50 by 冰火
@idior
等了这么久,还是没有人继续评论啊。

还是继续发表我的愚见。

对Transparent persistence的理解可能和你有所出入。

文章你所表现出来的Transparent persistence好像就是指对Insert,Update实现了透明处理,但我觉得对数据访问的透明,对不同数据库的透明才更加重要。

# re: Enterprise Persistence Design  回复   

2005-07-19 10:51 by 冰火
关于.Net的平台下表现层(UI Layer)的设计, 以及如何和当前的持久层(Persistence Layer)相结合

你具体是指什么?

# re: Enterprise Persistence Design  回复   

2005-07-19 10:53 by 冰火
和持久层相结合是指怎么将PO传递到UI,或者怎样将PO包装再传递到UI吗?

# re: Enterprise Persistence Design  回复   

2005-07-19 11:01 by 冰火
我所知道的方案是:
1、直接将PO传递到UI;
2、将PO包装成DTO(可能通过远程外观或Service),将DTO传递到UI;
3、将PO包装成VO(View object)再传递到UI,注意此处不用DTO,其实DTO通常是用在分布式,跨进程调用的情况;
3、将PO包装成DTO,再将DTO包装成VO(View object)传递到UI;

PO:持久对象,一般领域对象同PO指一个对象,当然也可以不一样。如hibernate对应的实体对象。
DTO:用于分布式环境的数据传输对象,他是粗粒度的。
VO:视图对象,指与UI对应的对象,如struts中ActionForm。

# re: Enterprise Persistence Design  回复   

2005-07-19 18:07 by idior
@冰火
加我msn吧, 发个邮件给我。

怎么没有人评论呢? 难道还是非技术话题大家感兴趣?
希望听到您的意见。

# re: Enterprise Persistence Design  回复   

2005-07-19 18:19 by 冰火
@idior
已给你留言,邮件应该发出去了吧。

# re: Enterprise Persistence Design  回复   

2005-07-19 18:37 by idior
@冰火
我这里的透明更重要的是指业务逻辑和persistence逻辑无关。也就是当业务逻辑中改变状态时,不需要调用xxxDAO.Update().
一旦出现这种语句业务逻辑就对persistence逻辑有依赖了,虽然只是一种接口依赖但是总没有不依赖好。
如果不使用高层的o/r m(比如hibernate),你是很难摆脱这种依赖的。

关于数据源的透明那靠o/r m来做非常方便,不是本文的重点。基本上任何一种o/r m,不管高层,低层都支持数据源透明。


你太谦虚了,已经加你了,不过你不在线。

# re: Enterprise Persistence Design  回复   

2005-07-19 19:55 by 冰火
@idior
---
业务逻辑中改变状态时,不要调用xxxDAO.Update()
---

我并没有说更新状态就一定要调用xxxDao.Update()啊。

你可以通过Unit of Work模式实现你说的透明性。

hibernate只是比较好的帮我们实现了基于元数据的o/r映射而已。不用我们自己写了。

我是十分赞同使用现成的成熟o/r m框架的。但我说的和o/r m完全不冲突。

你可以好好看看企业应用架构模式第9章到13章。

其实我所说的大部分东西都来源于企业应用架构模式。并没有什么太多原创的东西。

# re: Enterprise Persistence Design  回复   

2005-07-19 20:22 by 冰火
@idior
顺便问一句,企业应用架构模式你看完了吗?

# re: Enterprise Persistence Design  回复   

2005-07-19 20:40 by kw
About UI layer:
Have you checked out ‘Composite UI Application Block’ on ms website? I haven’t spent too much time on that yet, but I got an impression that it covers most requirements you are facing when building a smart client UI…

# re: Enterprise Persistence Design  回复   

2005-07-19 22:36 by 行知
很好的文章。我也一直在考虑这方面的问题。

不过按照这种思路设计,Domain 对象和Persistence 对象分开后,如果一个系统有100个表,就需要100个Persistence对象和100个对应的Domain对象,好像很麻烦呀。

# re: Enterprise Persistence Design  回复   

2005-07-19 22:48 by idior
@冰火
Unit of Work模式手工实现可是很恐怖哦, 其实hibernate就是帮我们做了这些工作,包括映射,Unit of Work,Lazy Load等等啦, 你不会自己去实现Unit of Work吧. :)
@kw
that is just for smartclient(not for web), it seems very good at smart client, and also very hot:) i haven't studied in it just downloaded it. will u write something about it. :)
@行知
一百个表的问题我还真没考虑过, 也未接触过那么大的应用.
不知道你以前是如何对待这种应用的?
这种思路可能不太适合, 不过没这种经验,也说不出什么来.

# re: Enterprise Persistence Design  回复   

2005-07-20 01:53 by kw
Have you considered how security (vertical layer) fit into this?

# re: Enterprise Persistence Design  回复   

2005-07-20 09:02 by 冰火
@idior
所以我是十分赞成使用现成的成熟o/r m框架啦。

不过实现一个满足自身项目需要的简易的o/r m还是相对不是那么难的。呵呵

所以我前面说了,我们的分歧不在这里吗。

我们的分歧主要是:
1、service layer的必要性。(我认为不是必要的)
2、domain layer是否一定不能包含数据访问服务调用的代码。
(我认为是可以的,因为不提取service layer时,你通常就的这么做,而且我一般也不用service layer,即使用了service layer,我还是可以在domain layer调用数据服务接口,我可以将service layer当作领域外观来使用,让它完全不包含应用逻辑)

# re: Enterprise Persistence Design  回复   

2005-07-20 09:30 by 冰火
@行知
---
不过按照这种思路设计,Domain 对象和Persistence 对象分开后,如果一个系统有100个表,就需要100个Persistence对象和100个对应的Domain对象,好像很麻烦呀。
---

为什么一定要将Domain object和Persistence object分开呢?通常情况下,Persistence就可以作为Domain object。

另外100个表一百个(通常不止)domain object也很正常啊,这也不算什么大项目。

即使再多,又不会是你一个人做,有什么麻烦的。

# re: Enterprise Persistence Design  回复   

2005-07-20 10:04 by James
感觉讲得不是很清楚。

# re: Enterprise Persistence Design  回复   

2005-07-20 10:09 by idior
@冰火
其实martin也对service的使用持一种比较暧昧(偏向不用)的态度, 那章都不是他写.

我觉得service layer是一个进行事务包装的好地方,并且利用它可以隔离persistence logic,就个人而言实际项目中可能我也可能不用它.

还有就是受j2ee session bean的影响, 在分布式环境下可能更需要facade来提供coarse-grained的接口,避免来回过多通讯.

其实o/r m一旦涉及到关联实现起来就会很麻烦.

@kw
能力所限尚未考虑,有没有什么好的指引性的意见.thanks.

@James
请问哪块讲的不清楚?

# re: Enterprise Persistence Design  回复   

2005-07-20 11:14 by kw
“好的指引性的意见”谈不上,只是我自己在这些方面迷惘和挣扎,所以想看看别人的看法。
现在参与的 smart client + web svc 的项目从 .NET beta 1 开始也蛮久的了,几个 solutions,每个 solution 几十,近百个 projects 也算是蛮复杂的,一直没有时间认真研究一下架构方面的 best practices。因为各种原因(历史原因,原有的 db schema,以前的版本兼容,项目原因,用户需求等等)使用了 dataset / databinding 的方案 (一般被认为是大型项目的大忌),曾经一度耿耿于没有使用 O/R mapping (尽管 DAL / BO 的实现借鉴了很多类似概念)。但是现在有时觉得有一次 VSLive 一个家伙说“dataset vs O/R mapping 不管你选择了哪个,都会觉得另一个更好”好像很有道理,sigh。因为现在觉得单纯使用哪一个问题好像都不大,但是把 cache / offline data support / security / inter-module communication 等等考虑进去,就都蛮复杂了。所以想看看大家在使用 O/R mapping 方案做复杂应用时,如何解决每个项目都要面临的那些问题。

# re: Enterprise Persistence Design  回复   

2005-07-20 11:58 by bje
1、确实缺少实例,很难让人理解你的模型的好处:P
2、“ Entity在很多时候成为了一个只有数据没有行为的"哑对象", 那么行为也就是业务逻辑哪去了?它们往往被放到XXXEntityManager中去了.“,这个XXXEntityManager是什么东东?domain object的管理器?好象不是那么回事。一般说Entity应该描述的是domain中的名词性概念,那么还有一些是动词性概念。但两者间没有什么直接的关联关系的。比如支票和公司的应付款业务间,并不实际存在关联关系(也就是说可能是use关系,而非association关系)。所以俺不太理解你说的XXXEntityManager是什么概念?至少在实际项目中很少见到这样的设计。比如总不会有一个支票对象,然后还有一个支票管理器对象吧????
这样,你所说的:“既然XXXEntityManager的任务就是围绕XXXEntity的数据做操作为什么不直接让XXXEntity自己做?”根本不可能。支票对象需要完成应付款业务吗???
3、你说的Hibernate可以实现transparent persistancy。这一点赞成。
4、我和冰火观点一样,service layer与transparent persistancy好象没有什么关系。
5、你说的Facade与俺理解的Facade好象不是一回事。因为在俺们做设计时,从来没有说Facade里面还有业务逻辑一说。这一段看得比较晕。请解释一下你理解的Facade。就我们而言,一般Facade只做所谓的coarse grind object的事,其主要目的是为了向外界提供一个干净的界面,不让其它程序员看到一堆domain object给吓坏了。俺觉得冰火这一点理解和俺是一样的,facade应该是use case的一种实现形式
6....等会儿,俺吃中饭去。:P

# re: Enterprise Persistence Design  回复   

2005-07-20 13:25 by 冰火
@bje
idior这里说的Facade应该不是指设计模式中的Facade,广义上的吧。

Service Layer包含应用逻辑也是很常见的方式。

包含应用逻辑的叫脚本外观,不包含应用逻辑的的叫领域外观(这个和设计模式中的Facade差不多)

领域外观,教本外观的称谓来源自企业应用架构模式。

# re: Enterprise Persistence Design  回复   

2005-07-20 15:46 by James
我觉得你没有很好地表达你的思想——模型画得不清楚,而且没有实例——能应用于实际开发的实例,而不仅仅是一些理论。

# re: Enterprise Persistence Design  回复   

2005-07-23 17:01 by Teddy's Knowledge Base
@idior:

Hibernate是个不错的ORM框架,但是,就你的论点来讲,我觉得不能评价对错,只能说基于Hibernate的这个解决方案还不错,可以用于解决很多问题,不过,你的字里行间,我总有种感觉就是,你在将各种现有问题,使劲往现有的Hibernate解决方案上靠,似乎Hibernate就是上帝,这一点让我感觉不是特别舒服~~

# re: Enterprise Persistence Design  回复   

2005-07-23 17:37 by Teddy's Knowledge Base
@idior:

再有,我不认为entity bean中包含save update这两个函数有什么问题,因为这只是两个函数接口而已,实际上,我觉得所谓“数据持久化透明”,本质是使数据持久化,但是无需知道具体被保存到哪里,在ejb的规范中,我想从来没有强制规定,这两个函数体内必须包含实际的持久化代码吧?因此,我认为,即使从纯oo的角度,我也觉得,包含这两个函数没什么问题,至少从语义上,这两个函数接口本身不会暴露你怎样持久化数据的细节,除非你认为domain object不该包含任何函数,否则,就算函数名不叫save,我可不可以写点持久化代码呢?

# re: Enterprise Persistence Design  回复   

2005-07-25 12:08 by idior
---
“数据持久化透明”,本质是使数据持久化,但是无需知道具体被保存到哪里
---
我说的不是这种透明, 这种透明所有的o/r m都能实现。

---
entity bean中包含save update
---
理论上不应该,从责任分离的角度,以及关注点分离的角度都不应该包含。

---
domain object不该包含任何函数,否则,就算函数名不叫save,我可不可以写点持久化代码呢?
---
理论上不要包含任何持久化代码。 业务层最好能做到只关心业务逻辑方面的事,而不考虑任何有关persistence,log,security,ui的事情,目前的纵多容器框架都是想实现这一目的。hibernate就是在分离persistence上做的比较好。

---
似乎Hibernate就是上帝,这一点让我感觉不是特别舒服
---
这里主要是描述Hibernate的优点,让大家认清什么是Hibernate。因为很多人用Hibernate的方法和观点是错误的,对Hibernate的认识也十分有限。

# re: Enterprise Persistence Design  回复   

2005-08-11 12:31 by clamphammer
我感觉Facade的职责很难区分,当做一个实际项目的时候会有这种感觉。
有可能facade里面包含了大量业务逻辑,这样可能造就贫血的domain object.
其实实体类和DAO这些代码基本都是相对固定的,就是那么几个属性和load,update,save等方法。

还是举个实际的例子比较好。没有例子,都是空对空的,讨论的价值会大大降低,毕竟模式都是是为解决实际问题而产生的。

其实计算工资的例子有很多东西可以研究:

员工属性:工号,姓名,电话,地址
职位:程序员,软件工程师,高级软件工程师,项目经理,系统分析员,技术总监,部门经理,总经理。
合同类型:临时工,合同工,实习工。
工资内容:基本工资,基本奖金,项目提成,加班津贴。扣除伙食费,福利金,所得税,借支。

说明:
实习工和合同工有基本工资。
临时工按工作日计算工资
合同工全有。
合同工和实习工有加班津贴
基本奖金的发放按该月实际工作天数
基本工资职位相关

目的:计算月实发工资。

设计要求:增加新的员工类型和新的合同类型时修改的源代码尽可能少。

给出类图即可。

# re: Enterprise Persistence Design  回复   

2005-08-11 17:54 by idior
@clamphammer
谢谢你的例子, 有空研究一下。

# re: Enterprise Persistence Design  回复   

2005-08-22 18:12 by Allen
谢谢,收藏!

# re: Enterprise Persistence Design  回复   

2005-09-13 18:14 by 蛙蛙池塘
不错,第一次看了一遍,好多不懂的,希望看第10遍的时候能完全看懂.

# re: Enterprise Persistence Design  回复   

2005-10-06 15:59 by kaven
好文章。
现在.net下面真正给开发项目的人看的文章太少了,多数就是在鼓吹技术,往往就说一个组件怎么用。真正开发项目如果按照这种方式做,更不不会节约开发成本,而且死得很难看。

# re: Enterprise Persistence Design  回复   

2005-10-06 16:04 by kaven
顺便问一下,有什么比较好的.net下,比较成熟的web企业级开发解决方案,可以推荐一下?

# re: Enterprise Persistence Design  回复   

2005-10-13 17:37 by hh
不是在讨论领域模型吗?怎么反过来考虑一百个表有一百个领域对象的问题了,PEAA里可是很清楚的说明关注于领域对象,重点是业务逻辑,怎么存储是之后的事情。不过实际中真这么做,难度很大,我们的项目基本上都是先有表,再有对象,呵呵。

从高层的结构来看,各种框架都差不多,所谓n层结构了,真正难的是怎么去设计实现,就如文中所说“如果你设计良好,组织好类与类之间的关系”,问题就在这里,要把类之间的关系组织好是很困难的,OO开发的重点其实也就在这里。真要把这些搞通了,也就是OO专家了。

好的OO设计真的很难啊,看看网上那些开源项目,Spring, Hibernate, Castle,都是老外搞得,国人简直没什么建树,真希望能看到国人搞得有价值的开源项目,而不是仅在网上侃侃而谈。

# re: Enterprise Persistence Design  回复   

2005-10-13 17:39 by hh
clamphammer的计算工资的例子可以去看“敏捷软件开发:原则、模式与实践”上的“薪水支付案例”

# re: Enterprise Persistence Design  回复   

2006-03-21 00:39 by liu.yuanhuo

posted on 2006-03-26 12:02  Arlen  阅读(350)  评论(0编辑  收藏  举报

导航