这两个概念是早些时候 Martin Fowler 总结出来的两种常见模型设计类型,没有说谁好谁不好,为不同的模型类别选择合适的场景是设计者的工作。没有工具本身的问题,只有工具使用者的问题。
贫血模型是指领域对象里只有 get 和 set 方法(POJO),所有的业务逻辑都不包含在内而是放在 Business Logic 层。
优点是系统的层次结构清楚,各层之间单向依赖,Client->(Business Facade)->Business Logic->Data Access Object。可见,领域对象几乎只作传输介质之用,不会影响到层次的划分。
该模型的缺点是不够面向对象,领域对象只是作为保存状态或者传递状态使用,它是没有生命的,只有数据没有行为的对象不是真正的对象,在 Business Logic 里面处理所有的业务逻辑,对于细粒度的逻辑处理,通过增加一层 Facade 达到门面包装的效果。
在使用 Spring 的时候,通常暗示着你使用了贫血模型,我们把 Domain 类用来单纯地存储数据,Spring 管不着这些类的注入和管理,Spring 关心的逻辑层(比如单例的被池化了的 Business Logic 层)可以被设计成 singleton 的 bean。
假使我们这里逆天而行,硬要在 Domain 类中提供业务逻辑方法,那么我们在使用 Spring 构造这样的数据 bean 的时候就遇到许多麻烦,比如:bean 之间的引用,可能引起大范围的 bean 之间的嵌套构造器的调用。
贫血模型实施的最大难度在于如何梳理好 Business Logic 层内部的划分关系,由于该层会比较庞大,边界不易控制,内部的各个模块之间的依赖关系不易管理,可以考虑这样这样的实现思路:
-
(1)铺设扁平的原子业务逻辑层,即简单的 CRUD 操作(含批量数据操作);
-
(2)特定业务清晰的逻辑通过 Facade 层来组装原子操作实现。
-
(3)给业务逻辑层实施模块划分,保持模块之间的松耦合的关系。
举例说明:
原子业务逻辑层(Service)提供了用户模型的条件查询方法:
List<User> queryUser(Condition con)
Facade 层则提供了一种特定的业务场景的分子接口,满足 18 岁的中国公民,内部实现调用的正是上述的原子接口:
List<User> queryAdultChinese()
Facade、Service 层纵向划分为几个大的领域包:用户、内容和产品。
充血模型层次结构和上面的差不多,不过大多业务逻辑和持久化放在 Domain Object 里面,Business Logic 只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成 Client->(Business Facade)->Business Logic->Domain Object->Data Access Object。
它的优点是面向对象,Business Logic 符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。
缺点是如何划分业务逻辑,什么样的逻辑应该放在 Domain Object 中,什么样的业务逻辑应该放在 Business Logic 中,这是很含糊的。即使划分好了业务逻辑,由于分散在 Business Logic 和 Domain Object 层中,不能更好的分模块开发。熟悉业务逻辑的开发人员需要渗透到 Domain Logic 中去,而在 Domian Logic 又包含了持久化,对于开发者来说这十分混乱。 其次,如果 Business Logic 要控制事务并且为上层提供一个统一的服务调用入口点,它就必须把在 Domain Logic 里实现的业务逻辑全部重新包装一遍,完全属于重复劳动。
使用 RoR 开发时, 每一个领域模型对象都可以具备自己的基础业务方法,通常满足充血模型的特征。充血模型更加适合较复杂业务逻辑的设计开发。
充血模型的层次和模块的划分是一门学问,对开发人员要求亦较高,可以考虑定义这样的一些规则:
-
(1)事务控制不要放在领域模型的对象中实现,可以放在 facade 中完成。
-
(2)领域模型对象中只保留该模型驱动的一般方法,对于业务特征明显的特异场景方法调用放在 facade 中完成。
万事都不是绝对的,也有一些看起来不易解决的问题。例如,考虑到性能的需要,我需要一次查询出满足某种条件的用户和某种条件的产品,他们二者之间通过订购关系关联起来,可能发现这种情形下,上述的模型层次划分变得无解了……
怎么办呢?包括以上种种,欢迎大家讨论。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》
我有个疑问,在充血模型的架构中,业务规则的校验应该如何实现,放在领域模型中吗?你有什么好的思路呢?
学习!看完楼主的这篇文章,解答了我心中很多的疑问!