设计模式、面向对象七:贫血模型与充血模型

前景

我们都知道,现在很多项目都是基于贫血模型的MVC三层框架。
虽然这种开发模式已经成为了标准的web项目的开发模式,但是它却违反了面向对象的编程风格,是一种彻底的面向过程的编程风格,因此有人称之为反模式

什么是MVC

MVC三层架构中,M表示Model, V表示View,C表示Controller。将整个项目分为三层:展示层、逻辑层、数据层。不过很多项目也不会100%遵从MVC固定的分层方式,而是会根据项目具体需求做适当调整。比如很多的web项目都把后端项目分为Repository层、Service层、Controller层。

  • Repository层负责数据访问
  • Service层负责业务逻辑
  • Controller层负责暴露接口
什么是贫血模型?

举个例子


// Controller+VO(View Object) //
public class UserController {
  private UserService userService; // 通过构造函数或者 IOC 框架注入
  
  public UserVo getUserById(Long userId) {
    UserBo userBo = userService.getUser(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;
}

这是一个正常的web后端代码,从代码中,可以发现,UserBo是一个纯粹的数据结构,只包含数据,不包含任何业务逻辑。业务逻辑都集中在UserService中。我们通过UserService来操作UserBo。换句话说,Service层的数据和业务逻辑都被分隔在BO和Service两个类中。
像UserBo这样,只包含数据,不包含业务逻辑的类,就叫做贫血模型

什么是充血模型

充血模型和贫血模型刚好相反,数据和对应的业务逻辑被封装到同一个类中。因此,充血模型满足面向对象的封装特性,是典型的面向对象编程风格

什么是领域驱动设计

领域驱动设计,即DDD,主要是用来指导如何解耦业务系统,划分业务模型,定义业务领域模型及其交互。
在基于充血模型的DDD开发模式中,Service层包含Service类和Domain类两部分,Domain就相当于贫血模型中的BO。不过DOmain与BO的区别在于它是基于充血模型开发的,既包含数据,也包含业务逻辑。而Service类变得非常单薄。
做好领域驱动设计的关键是,看你对自己所做的业务的熟悉程度,而不是对领域驱动设计这个概念本身的掌握程度
总结一下: 基于贫血模型的开发模式,重Service轻BO;基于充血模型的DDD开发模式,轻Sercie重Domain

为什么基于贫血模型的传统开发模式如此受欢迎
  • 通常情况,开发的系统业务比较简单,简单到就是基于sql的crud操作,所以不需要动脑子精心设计充血模型,除此之外,因为业务简单,即便使用了充血模型,那模型的业务逻辑也并不会很多,设计出来的领域模型比较单薄,和贫血模型差不多,没太大意义
  • 充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格。我们从一开始就要设计好针对数据要暴露那些操作,定义那些业务逻辑。而不像贫血模型那样,只需要定义数据,之后有什么功能开发需求,直接在service定义什么操作,不需要事先做太多设计
  • 思维已固化,转型有成本
什么项目应该考虑使用基于充血模型的DDD开发模式

在我们平时的开发中,我们大部分就是SQL驱动(SQL-Driven)的开发模式。 我们接到一个后端接口需求的时候,就去看接口需要的数据对应到数据库中,需要哪张表或者哪几张表,然后思考如何编写sql语句来获取数据。之后就是定义Entity、BO、VO,然后模板式的给对应的Repository、Service、Controller类添加代码。
业务逻辑包裹到一个大的sql语句中,而service层可以做的事情很少,sql都是针对特定的业务功能编写的,复用性。当要开发另外一个业务功能的时候,只能重新写个满足新需求的sql,这就可能导致各种长得差不多,区别很小的sql语句遍地都是。
所以在这个过程中,很少有人会应用领域模型、OOP的概念,也很少有代码复用意识,对于简单业务系统来说,这种开发方式问题不大。但对于复杂业务系统的开发来说,这样的开发方式会让代码越来越混乱,最终导致无法维护。

如果在项目中,应用基于充血模型的DDD的开发模式,那对应的开发流程完全不一样。在这种开发模式下,我们需要实现理清楚所有业务,定义领域模所包含的属性和方法。领域模型相当于可复用的业务中间层。 新功能需求的开发,都基于之前定义好的这些领域模型来完成。

越复杂的系统,对代码的复用性、易维护性要求就越高,我们就越应该花更多的时间和精力在前期设计上,而基于充血模型的DDD开发模式,正好需要我们前期做大量的业务调研、领域模型设计,所以它更加适合这种复杂系统的开发

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
面向过程的贫血模型面向对象充血模型是软件开发中常见的两种设计模式面向过程的贫血模型是一种基于过程的设计方式,其中数据和处理逻辑被分离。在这种模型中,数据结构被定义为简单的数据对象,而处理逻辑则由一系列函数或过程来操作这些数据。贫血模型中的数据对象通常只包含属性,并且缺乏行为和方法。处理逻辑主要由外部的控制器函数或过程来实现。 相比之下,面向对象充血模型是一种将数据和处理逻辑封装在一起的设计方式。在这种模型中,数据被定义为对象,并且对象拥有自己的属性和方法。对象之间可以相互交互和通信,通过方法来操作和修改数据。充血模型更加注重对象的行为和方法,强调对象的内聚性和封装性。 面向对象充血模型相比于面向过程的贫血模型具有以下优点: 1. 更好的封装性和信息隐藏:对象将数据和相关操作封装在一起,外部无法直接访问和修改内部状态,提高了代码的安全性和可维护性。 2. 更好的扩展性和灵活性:通过继承、多态等特性,可以方便地扩展和修改代码,适应变化的需求。 3. 更高的可读性和可理解性:充血模型将逻辑和数据组织在一起,代码更加直观和易于理解。 4. 更好的复用性:通过对象的组合和复用,可以减少代码的重复性,提高开发效率。 然而,面向过程的贫血模型在某些场景下也有一定的优势,比如简单的算法实现或者临时脚本。选择使用哪种设计模式应该根据具体的项目需求和开发目标来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值