看了楼主的文章,对楼主主要论点是赞同的。就是做三层不能为三层而三层,而应该看具体项目。三层并不是包治万病的万能药,而应该针对不同的项目选用不同的框架。但楼主的文章在对比两种方案优劣(感觉是对比了单层的优和多层的劣)之后,并没有对哪种项目应选用哪种框架展开讨论。因此这里我想谈谈这方面的看法。我的观点在细节上也许与楼主会有些出入,但主要论点是一样的,三层并不适用于所有项目,当然,有一些项目比较适合用三层来做。
对于三层框架在相对简单(非企业应用)的项目中的劣势,我觉得楼主分析得很到位。在Fowler的《Patterns of Enterprise Application Architecture》中也明确说明,选用Domain Model是应该很慎重的。选用了Domain Model,就必须有一大套相关的模式与之对应,例如OR MAPPING,Unit of Work等等。
有一点需要说明,在PEAA一书中,Domain Model是专指一个对象对应一个实体映射的模式,而且Domain Model层应该是不依赖于表达层,也不依赖于数据层。因此我不赞同楼主关于“逻辑层对数据访问层直接依赖”的说法。这种说法掩盖了Domain Model的一个重要优点:Domain Model的开发人员并不需要了解数据层接口细节(注意是接口细节,楼主的框架中只是通过数据层接口封装了数据层实现细节,但逻辑层开发人员必须了解数据层接口,这直接导致了原文1.4中讨论可扩展性时出现修改点太多的问题)。对于轻型的持久框架,要实现这个特性一般有两种做法,一是用软件对编译后的中间代码进行处理,插入数据层操作代码;一是使用一些逻辑层(甚至表达层)可见的通用数据管理类来实现持久对象数据的载入和保存。对于大型的持久框架,一般是由容器类来管理持久对象的载入与保存。现在市面上的大部分比较成熟的持久方案,都比较依赖于反射机制。因此对于没有反射机制的DLEPHI (7.0之前, .net我没用过),是一个很不利的地方。
一个完善的基于Domain Model与成熟的持久平台的项目,优势在于Domain Model的单纯。因为单纯,开发人员可以专心于业务逻辑。因为单纯,开发人员可以应用任何面向对象技术而不会直接或间接地被数据库结构钳制。而正如楼主在1.3节所说,劣势在于因此引入的复杂度。整体来说,我认为Domain Model的框架的指导思想是,牺牲系统的整体复杂度,来换取逻辑层的相对简单。但如果系统的主要复杂度与可预见的变动并不是集中于业务逻辑层(很可能你在编写的不是企业应用),那么使用Domain Model的三层就是在自找苦吃。
楼主在1.4节中从另一个方面说明了同样的问题,Domain Model三层在发生非业务逻辑为主的变动时相对复杂。举增加用户性别的例子,这个需求变动是数据结构变动(因此造成AddStudent接口变动),而引发的系统变动主要涉及表达层与数据层。在这种情况下,Domain Model就显得十分笨拙了。但严格来说,我觉得楼主选用这个例子说服力并不够,因为这个例子有点特殊:
1.涉及到修改数据库结构。实话说,对于任何已经在运行的系统,这都是大忌。必定涉及一系列改动。在这个例子中,又同时需要根据数据库内容直接改变界面内容。这种纵向的变动这是任何分层结构的死穴,必定涉及到自最顶(表达层)到最底(数据层)的改动。中间层数越多,就越复杂。而处理这种变动最得心应手的,自然是界面代码直接操作数据库的单层结构了。这是以己之极长攻敌之极短的一个特例。
2.例子中加入性别一项,仅仅是为了显示。完全只涉及界面与数据库的直接对应。但如果这个新增属性会引起业务逻辑一系列变动。而这些变动很有可能用到一些公共的公式算法,SQL语句等等,单层框架无可避免的就会出现重复代码。如果你把这些公共部分独立出来做成函数来调用。那么恭喜你,你已经堕入了分层的陷阱,以后如果再加入新属性,很可能这些函数的签名也需要跟着改变。然而由于在设计时并没有分层的意识,你会发现这些零散的函数与SQL语句分布在系统各处……
因此,有一种情况是绝对不应该用多层的。就是你发现,或者可以预见到:
1.客户对自己的需求极不明确,由于某些客观原因你也不可能搞明确,以致会在未来一段长时间中频繁修改数据库结构;而且
2.这些数据库变动的属性(添加,删除,修改)主要是用于显示,而极少影响主要业务逻辑;而且
3. 系统的业务逻辑并不极其复杂。
我认为Domain Model三层跟许多“封装”型的结构一样,是很受“酒与污水定律”影响的。所谓“酒与污水定律”,就是:“如果你把一杯酒倒进一桶污水,你得到一桶污水;如果你把一杯污水倒进一桶酒,你得到的还是一桶污水”。在使用Domain Model三层的过程中,任何地方不遵守封装与分层的原则而出现“泄漏”或者“重复代码”的话,所有努力就白费了。而且还会造成误导,因为一直做单层的人,他做任何改动必然会全局检查。然而一个貌似多层的系统,他在修改业务逻辑的时候就不会去留意,在表达层的某个角落,有段代码正在直接访问数据库而绕过了他的修改。如果你能预见到,日后你会因为赶进度而不遵守三层规则,又或者日后小修小改的维护人员根本不会用三层,那么从一开始你就不应该用。
最后想说明一点是,Domain Model三层作为一种比较精纯的面向对象框架,还有一个优势是逻辑层能享受很多面向对象的技术与工具支持。例如面向对象需求与系统分析,还有各种基于面向对象的设计模式,以及各种单元测试工具,重构技术。相对来说,其他分层模式,例如Active Record, Table Module也能应用这些技术与工具。但毕竟逻辑结构受到数据库结构限制,不能得心应手。但这一切都是以复杂度为代价的,也就是说,必须在逻辑层的灵活性与系统整体复杂度之间找到平衡点。