写点什么

设计模式之美 -- 后端 MVC 框架和贫血模型、充血模型

作者:GalaxyCreater
  • 2022-11-30
    广东
  • 本文字数:2117 字

    阅读完需:约 7 分钟

MVC 框架(model、view、controller)


后端项目分为 Repository 层、Service 层、Controller 层。其中,Repository 层负责数据访问,Service 层负责业务逻辑,Controller 层负责暴露接口。


贫血模型 MVC 框架示例

////////// Controller+VO(View Object) //////////public class UserController {  private UserService userService; //通过构造函数或者IOC框架注入    public UserVo getUserById(Long userId) {    UserBo userBo = userService.getUserById(userId);    UserVo userVo = [...convert userBo to userVo...];    return userVo;  }}
public class UserVo {//省略其他属性、get/set/construct方法 private Long id; private String name; private String cellphone;}
////////// Service+BO(Business Object) //////////public class UserService { private UserRepository userRepository; //通过构造函数或者IOC框架注入 public UserBo getUserById(Long userId) { UserEntity userEntity = userRepository.getUserById(userId); UserBo userBo = [...convert userEntity to userBo...]; return userBo; }}
public class UserBo {//省略其他属性、get/set/construct方法 private Long id; private String name; private String cellphone;}
////////// Repository+Entity //////////public class UserRepository { public UserEntity getUserById(Long userId) { //... }}
public class UserEntity {//省略其他属性、get/set/construct方法 private Long id; private String name; private String cellphone;}
复制代码

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 开发模式,正好需要我们前期做大量的业务调研、领域模型设计,所以它更加适合这种复杂系统的开发。


发布于: 刚刚阅读数: 3
用户头像

GalaxyCreater

关注

还未添加个人签名 2019-04-21 加入

还未添加个人简介

评论

发布
暂无评论
设计模式之美--后端MVC框架和贫血模型、充血模型_设计模式_GalaxyCreater_InfoQ写作社区