我想,初学者、交流者都希望有一个真正的代码模型临摹学习才是最终结论,无论上面各位说的是否认为完美情况,因为实际情况千变万化。我个人觉得OO内部涉及的pojo会包含一些逻辑映射,例如:两种类似的对象存放一个表内。如果分开设计可以避免但是会出现数据部分维护困难或者不符合数据设计的三范式。

论实际过程,表示层-服务层-逻辑层-持久层,这种设计我个人认为并不适合对于初期开发的构建,对于多层次的调用查代码是非常困难,除非业务是复杂的、嵌套的,要是初期开发就有这类需求则必须使用以上结构,对于普通的业务性增删查改等简单性操作,我个人认为还是贫血模型比较实际简单,维护方便,可以说项目的70%都是这类的操作。一个项目在开发期可以先使用贫血模型,在业务增加的时候作重构工作,这时候加入服务层,而且是两种结构同时存在。项目是不断的重构扩展的,不可能一成不变。

谈下实际代码结构问题,表示层显示数据通常都是针对多表或者多对象嵌套的二维结构显示,对于持久层映射目标是把数据库带逻辑的二维结构转换为三维或者多维结构。这种转化就目前情况而言即使最好的orm都并不能全部使用持久层框架进行转化,多数情况下必须手动进行代码或者使用框架的查询语句进行查询组合,组合出来后还需要代码性质转换,在开发者角度可以说是一种负累,框架应该是减负的工具。(说一下的小经历,曾经到一间公司面试,面试官居然说,使用算法去转换,这样一来程序员的能力要求需要高了。到此处以致懂某某orm会薪水高些)

请大家考虑以上问题,不要说是人的素质,能力问题。因为这是普篇问题,可以说我见过的代码中非常多这种情况。而且这些代码都出自高谈阔论的程序员手中。实际与说是两码事,这确实存在于我们当中,希望各位给出正解。

(以上谈到的算法与通用算法会有很大出入,通常是业务逻辑夹杂的业务算法。这种代码维护是非常困难的。)

>初学者、交流者都希望有一个真正的代码模型临摹学习才是最终结论
我个人认为我本人开发的JiveJdon3应该是一个这样代码模型之一,它比较类似前面那种社区类网站案例。

>表示层显示数据通常都是针对多表或者多对象嵌套的二维结构显示,对于持久层映射>目标是把数据库带逻辑的二维结构转换为三维或者多维结构,..组合出来后还需要代码性质转换,在开发者角度可以说是一种负累.
>..因为这是普篇问题,可以说我见过的代码中非常多这种情况。实际与说是两码事,>这确实存在于我们当中,希望各位给出正解。

不知santafeng想求的正解是否是前面所说的表现层和持久层进行转换是一个负累,这在实际开发中存在的。我个人认为可能无法框架来解决,还是需要人的OO素质。

我初期的观点是:如果我们首先没有建立代码模型,不去忘记数据库,就会存在这种为撮合而进行的转换现象;当然也不能一概而论。特别是查询结果,查询结果我们可以分解为几个对象的组合,总之,以实体对象为核心,必然会有围绕该实体对象的多个shadow对象,或者称Proxy对象,或者使用继承来表达,总之可以使用多种OO设计范式来表达。

当然,以上也属于"高谈阔论",欢迎交流。


框架(架构):目标只有一个更好更快的完成任务。如果不能帮助我们实现以上目标用它干嘛,对可能有人认为用某种架构框架价格可以提升,利润可以翻倍。

我的想法很简单,什么东西可以尽快完成任务,并且可维护性与扩展性都符合要求就使用那种设计,不能盲目要求从对象建模开始撇开表数据模型。


我从事的项目都是以大量的类似对象,相似的对象存放在同一张表内进行数据汇总等业务逻辑处理。若干个对象进行表现层和持久层(二维->三维)(三维->二维)转换,这种转换的代码是非常惊人的,这类代码维护比维护一条不可移植的sql困难多了。


盲目的追寻oo对象模型设计忽略了传统数据库模型设计,作出是一个维护成本高的系统。对于这类系统,投资者是不赞同的,开发员只能靠重复的加班实现,最后系统可能会遭遇失败。

>若干个对象进行表现层和持久层(二维->三维)(三维->二维)转换,这种转换的代>码是非常惊人的

我们需要对出现这种现象的本质有一个认识,下面我谈我比较赞同的一个观点:
出现这种现象本质就是关系数据和对象之间匹配Mismatch造成的,也就是说是水和火本身就是很难相容,我们硬是将它们组合在一起,虽然有Hibernate之类ORM框架帮忙,但是不能从根本上改变,就象两个性格完全不同的人或信念不同的人,就是有一个中间者调解,也不能说以后就消除了分歧,所以大量成本就花费这种调和中,这种现在在社会现实很多,很多社会成本就是花费在调解上了。

解决这种问题的方式也显而易见,就是消灭一方,这种方式在社会中只能通过战争和其他革命手段达到(也未必能够达到),在技术世界中,就是采取完全OO路线替代关系数据库路线,或者干脆就是纯粹的关系数据库路线,如果试图在一个软件系统中都存在OO路线和数据库路线,当然迟早出现各种转换代价。

OO路线完全替代数据库路线属于一种革命性极端的手段,个人认为也是一种理想阶段,因为按照这样,可能代价更大(但是我一直在尝试,而且进展顺利,代价大就是一代程序员可能需要下岗,要么转换思路,一批系统要停止维护直至停用)。这里面就有一个权衡关系了:要么就付出象santafeng 出现那种转换累人代价,要么就要付出完全采取OO路线后这种创新尝试后的失败代价。还有一种,就是完全回到关系数据库时代,这可能就是倒退了。

谁还有能够更好办法呢?

帮人打工,就得遵守别人的游戏规矩。
做软件开发,必须在时间,成本,质量三者之间取得平衡。
我觉得表现层跟业务层转化的不多
业务层与数据库之间架一层转化器
象使用COMMON-BEANUTILS这些包不都可以大量节省代码么

如对于Lazy-load之类的问题则可以通过仓储和工厂解决


能不能举个例子?

>>帮人打工,就得遵守别人的游戏规矩。
>>做软件开发,必须在时间,成本,质量三者之间取得平衡。
正确,不能盲目追求。需实事求是,所以我认为贫血模型更实用。

>>我觉得表现层跟业务层转化的不多
看你项目的设计而定,如果都把业务对象参数抽离成为一种类型存放的时候转换就会很多。如:开放/关闭 在字段内用0,1表示,另外参数对象是对应的属性:0,1.名称:开放/关闭(不要说在页面上做判断性显示,这样会增加维护量)

>>业务层与数据库之间架一层转化器
>>象使用COMMON-BEANUTILS这些包不都可以大量节省代码么
COMMON-BEANUTILS只能复制相同属性的对象值,对于表示层-服务层-逻辑层-持久层之间的值对象属性命名必须统一,并且存值对象的命名问题争议很大,分层越多,代码值对象使用的管理规范复杂,程序员可控性失效。如:用户权限模块,一个列表排列,可能程序员会编写这样的值对象,表示层User-服务层UserPower-持久层Oper.可能我举的用户例应该不会出现这种情况,但在很多业务需求的时候程序员往往会这样做(这里只是举例了对象名称不同,而且实际中还有内部的属性名)。若接手的程序员维护就非常麻烦。


[该贴被santafeng于2007年07月05日 12:43修改过]

bang难道也如此迂腐吗?对这种细节如此纠缠不清。老外都是从方法论来看待问题,至于具体细节的把握。都是靠设计师对业务的理解程度,至于细节上如何把握,只要设计师自己觉的流畅,可把握就可以了。一切凭感觉。倒没有必要“贫血模型“什么的帽子乱扣。至于先数据建模还是先设计实体,只是形式不同而已,也没有必要 分谁对谁错。主要的业务领域模型在早期的分析阶段已经比较清楚了。
事实上,开始进行数据建模的时候,设计师已经对业务领域模型有比较深刻的了解。

另外无论分析设计,编码都是一个迭代的过程,只要开始大方向不错就可以。其实就象数学一样,就那么浅显的几条公理做基础。

”贫血模型“就不是oo了吗?oo最基础的概念就是面向接口,照我的理解:将复杂业务里的公共稳定的部分抽取出来,如果这部分的具体实现是易变的,就把它形成interface.设计模式里除了一些技巧性的东西外,其它的不外是这么一个概念,只是将这些interface按现实世界的概念做了一些分类。

题外话,一直有点困惑:象hibernate这种o/r mapping实现,在系统层次里只应该属于一个很狭隘的层次里的一种选择而已,怎么会如此火热呢?

oo
oriented object

“照我的理解:将复杂业务里的公共稳定的部分抽取出来,如果这部分的具体实现是易变的,就把它形成interface.设计模式里除了一些技巧性的东西外,其它的不外是这么一个概念,只是将这些interface按现实世界的概念做了一些分类。

是这样吗?


面向接口 难道不是多态吗?
设计模式中的一部分难道不是将条件逻辑交于vm来做, 让于动态绑定来做吗?

其实DDD同样的面向接口的编程,它的理论主要是重视业务层,也同样可做为一样框架在行业中运用.

这么经典的帖子,给顶起来吧,大家再继续讨论下,我有个疑问:
对于DAO和仓储的区别的困惑,楼主说了对于CRUD采用DAO,但是对于查询要使用仓储,有什么区别吗?DAO本身就是数据访问对象啊,这两个本质差在哪?
或者是从领域模型,和领域有关的逻辑方面考虑的吧,请给予解答。
也请高手门在这里再次把DDD的谈论进行到底,呵呵!

>对于CRUD采用DAO,但是对于查询要使用仓储
Dao比仓储更低,有仓储来调用,仓储主要目的是封装SQL和对象之间的转换,也就是说:这里是对象和数据库的分水岭,是水与火的交接处。

在仓储也包含CRUD操作,这些操作必须包括完整聚合关系,保证不变性,比如帖子和论坛之间就是不变性,汽车和汽车发动机和车身都是不变性的,这些都要在仓储完成,比如保存汽车时,必须对汽车发动机和车身一同做保存,而且必须依赖事务全部锁定,只有一个用户才能操作;查询汽车时,也必须给汽车组装好汽车发动机等,当然这里面涉及工厂模式和Builder模式。

总之,从仓储出来的都是像样的领域模型,仓储中这种主对象和从对象的一致性也可以通过框架,比如JPA/Hibernate实现,不必自己做了。而DAO则和数据表结构有关系,属于数据库派的;而仓储是地道的领域对象派。

听了解答,豁然开朗,谢谢了!这个帖子真的很经典,不让他陈了,小弟有关于DDD的问题再发上来,让该贴永远浮着呵呵!
是否可以这样理解仓储和DAO,DAO中只负责数据的存储也就是与数据库交互,并不设计业务逻辑的问题,所以如果CRUD操作不设计具体的领域逻辑,就在service层中引用DAO完成实体对象的CRUD操作就OK了。
但是对于含有领域逻辑的操作,就需要利用仓储来进行,仓储是位于DAO的上层,纯属于领域的范畴,这个时候在service层中关联的就应该是仓储而不是DAO了,因为在DAO中是不应该存在业务逻辑这样的代码的,而这些代码是应该放置在仓储中,在仓储中处理完领域的问题之后,才把处理完的实体通过dao存储到数据库中!
以上是我看了banq的解答后的感受,不知道对不对?
[该贴被yongbuyanbai于2008-08-22 11:42修改过]