设计模式之美 -- 后端 MVC 框架和贫血模型、充血模型
MVC 框架(model、view、controller)
后端项目分为 Repository 层、Service 层、Controller 层。其中,Repository 层负责数据访问,Service 层负责业务逻辑,Controller 层负责暴露接口。
贫血模型 MVC 框架示例
Service 层的数据和业务逻辑,被分割为 BO 和 Service 两个类中。像 UserBo 这样,只包含数据,不包含业务逻辑的类,就叫作贫血模型(Anemic Domain Model)。同理,UserEntity、UserVo 都是基于贫血模型设计的。这种贫血模型将数据与操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。
基于充血模型的开发模式
充血模型(Rich Domain Model)正好相反,数据和对应的业务逻辑被封装到同一个类中。因此,这种充血模型满足面向对象的封装特性,是典型的面向对象编程风格
除了监控、调用链追踪、API 网关等服务治理系统的开发之外,微服务还有另外一个更加重要的工作,那就是针对公司的业务,合理地做微服务拆分。而领域驱动设计恰好就是用来指导划分服务的。所以,微服务加速了领域驱动设计的盛行。
不过,我个人觉得,领域驱动设计有点儿类似敏捷开发、SOA、PAAS 等概念,听起来很高大上,但实际上只值“五分钱”。即便你没有听说过领域驱动设计,对这个概念一无所知,只要你是在开发业务系统,也或多或少都在使用它。做好领域驱动设计的关键是,看你对自己所做业务的熟悉程度,而并不是对领域驱动设计这个概念本身的掌握程度。即便你对领域驱动搞得再清楚,但是对业务不熟悉,也并不一定能做出合理的领域设计。所以,不要把领域驱动设计当银弹,不要花太多的时间去过度地研究它。
基于充血模型的 DDD 开发模式实现的代码,也是按照 MVC 三层架构分层的。它跟基于贫血模型的传统开发模式的区别主要在 Service 层。
在基于充血模型的 DDD 开发模式中,Service 层包含 Service 类和 Domain 类两部分。Domain 就相当于贫血模型中的 BO。不过,Domain 与 BO 的区别在于它是基于充血模型开发的,既包含数据,也包含业务逻辑。而 Service 类变得非常单薄。总结一下的话就是,基于贫血模型的传统的开发模式,重 Service 轻 BO;基于充血模型的 DDD 开发模式,轻 Service 重 Domain。
为什么贫血模型比充血模型更受欢迎?
贫血模型实际上是面向过程的编程风格,有种种弊端,比如,数据和操作分离之后,数据本身的操作就不受限制了。任何代码都可以随意修改数据。
受欢迎原因:
第一点原因是,大部分情况下,我们开发的系统业务可能都比较简单,简单到就是基于 SQL 的 CRUD 操作,所以,我们根本不需要动脑子精心设计充血模型,贫血模型就足以应付这种简单业务的开发工作。
第二点原因是,充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格
第三点原因是,思维已固化,转型有成本。
什么时候考虑使用充血模型的 DDD 开发模式?
答:复杂业务。
继续问:这两种开发模式,落实到代码层面,区别不就是一个将业务逻辑放到 Service 类中,一个将业务逻辑放到 Domain 领域模型中吗?为什么基于贫血模型的传统开发模式,就不能应对复杂业务系统的开发?而基于充血模型的 DDD 开发模式就可以呢?
继续答:贫血模式大部分是 SQL 驱动的开放模式。 面对业务的时候首先根据具体情况定义表结构,然后看通过那些 SQL 操作能满足业务。然后就是定义 Entity BO VO 最后向 Repository Service Controller 类中添加相应的代码。 这种形式的编程,一个是代码的复用性太差,稍微不同一点的业务就需要新的接口,可能导致类似的 SQL 和接口太多。
所以:越复杂的系统,对代码的复用性、易维护性要求就越高,我们就越应该花更多的时间和精力在前期设计上。而基于充血模型的 DDD 开发模式,正好需要我们前期做大量的业务调研、领域模型设计,所以它更加适合这种复杂系统的开发。
版权声明: 本文为 InfoQ 作者【GalaxyCreater】的原创文章。
原文链接:【http://xie.infoq.cn/article/1808174fed54b1c94adb2b599】。文章转载请联系作者。
评论