贫血模型和充血模型

贫血模型(Anemic Domain Model)

  • 贫血模型是一种领域模型,其中领域对象包含很少或没有业务逻辑。是一种面向过程的编程模式,它与面向对象设计的基本思想相悖,将数据和过程结合在一起。
  • 因为贫血模型没有逻辑实现,所以逻辑基本上会放到调用贫血模型的service中,这些service类会转换领域对象的状态。
  • 贫血模型中,domain包含了不依赖于持久化的原子领域逻辑,而组合逻辑在Service层。service :组合服务,也叫事务服务。model:除包含get set方法,还包含原子服务(如获得关联model的id)。dao:数据持久化。

举例(MVC框架)

MVC 三层架构中的 M 表示 Model,V 表示 View,C 表示 Controller。它将整个项目分为三层:数据层、展示层、逻辑层。
我们一般就将后端项目分为 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.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;
}
  • 从代码中我们可以看到UserVo,UserBo,UserEntity 只包含数据,不包含业务逻辑的类,就叫作贫血模型。
  • 这种贫血模型将数据与操作分离,这种分离直观上就是不在同一个类里,就和一个车只有车的特点,但是不能开一样。破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。

贫血模型的优点

  • 贫血模型的系统层次结构清楚,各层之间单向依赖
  • 领域对象几乎只作传输介质之用,不会影响到层次的划分

贫血模型的缺点

  • 对象状态和行为分离(贫血模型中,对象只有属性,get/set方法,业务逻辑在不在对象类内部),所以一个完整的业务逻辑描述不能在一个类中完成,而是一组相互协作的类共同完成的。
  • 不够面向对象,领域对象只是作为保存状态或者传递状态使用,它是没有生命的,只有数据没有行为的对象不是真正的对象。(在service里面处理所有的业务逻辑,对于细粒度的逻辑处理,通过增加一层Facade达到门面包装的效果)
  • 可复用的颗粒度比较小,代码量膨胀很厉害,很重要的一点是业务逻辑的描述能力较差,一个稍微复杂的业务逻辑,就需要太多类和太多代码去表达。

说明

在使用Spring的时候,通常暗示着你使用了贫血模型

充血模型(Rich Domain Model)

  • 数据和对应的业务逻辑被封装到同一个类中。因此,这种充血模型满足面向对象的封装特性,是典型的面向对象编程风格。
  • 业务逻辑集中在 Service 类中。基于充血模型,Service 层包含 Service 类和 Domain 类两部分。Domain 是基于充血模型开发的,既包含数据,也包含业务逻辑。而 Service 类变得非常单薄。
  • 充血模型中,绝大多业务逻辑都应该被放在domain里面,包括持久化逻辑,而Service层是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。service :组合服务也叫事务服务;model:除包含get set方法,还包含原子服务和数据持久化的逻辑

优点

  • 对象自治度很高,表达能力强,适合于复杂的企业业务逻辑实现,可复用程度高。

缺点

  • 如何划分业务逻辑,什么样的逻辑应该放在Domain中,什么样的业务逻辑应该放在Service 中,这是很含糊的。
  • 对象自治度高的结果就是不利于大规模团队分工协作。

失血模型

  • 失血模型中,domain只有属性的get set方法的纯数据类,所有的业务逻辑完全由Service来完成的,没有dao,Service直接操作数据库,进行数据持久化。失血模型service层负担太重,一般不会有这种设计。

涨血模型

  • 胀血模型取消了Service层,只剩下domain object和DAO两层,在domain的domain logic上面封装事务。

为什么贫血模型受欢迎

  • 开发的系统业务可能都比较简单。贫血模型就可以应付,不需要充血模型。大部分是基于 SQL 的 CRUD 操作,我们不需要动脑子精心设计充血模型,贫血模型足以应付这种简单业务的开发工作。除此之外,因为业务比较简单,即便我们使用充血模型,那模型本身包含的业务逻辑也并不会很多,设计出来的领域模型也会比较单薄,跟贫血模型差不多,意义不大。
  • 充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格。我们从一开始就要设计好针对数据要暴露哪些操作,定义哪些业务逻辑。而不是像贫血模型那样,我们只需要定义数据,之后有什么功能开发需求,我们就在Service 层定义什么操作,不需要事先做太多设计。
  • 思维固化,转型有成本。基于贫血模型的传统开发模式经历了这么多年,已经深得人心、习以为常。如果转向用充血模型、领域驱动设计,有一定的学习成本、转型成本。

什么场景下使用充血模型

  • 我们平时的开发,大部分都是 SQL 驱动(SQL-Driven)的开发模式。接到一个后端接口的开发需求的时候,就去看接口需要的数据对应到数据库中,需要哪张表或者哪几张表,然后思考如何编写 SQL 语句来获取数据。之后就是定义 Entity、BO、VO,然后模板式地往对应的Repository、Service、Controller 类中添加代码。
  • 业务逻辑包裹在一个大的 SQL 语句中,而 Service 层可以做的事情很少。SQL 都是针对特定的业务功能编写的,复用性差。当我要开发另一个业务功能的时候,只能重新写个满足新需求的 SQL 语句。
  • 对于简单业务系统来说,这种开发方式问题不大。但对于复杂业务系统的开发来说,这样的开发方式会让代码越来越混乱,最终导致无法维护。
  • 在这种开发模式下,我们需要事先理清楚所有的业务,定义领域模型所包含的属性和方法。领域模型相当于可复用的业务中间层。新功能需求的开发,都基于之前定义好的这些领域模型来完成。
  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值