什么是贫血模型和充血模型?

一、贫血模型
日常我们在做项目时,通常会像如下代码一样定义一个实体:

public class Student {
    private int age ;
    private String name ;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

这也正是我们大多数人眼中所谓的”封装“:即隐藏内部实现细节,只对外提供get/set这些公共访问接口。
在日常项目中,我们也会把大部分的业务逻辑实现都写到service层里,而不是写在我们的实体类中。
其实这就是我们所说的贫血模型:即实体类中只包含了对象的属性以及属性的get、set方法,不包括该对象的具体行为,也就是业务逻辑都放在了我们的service层
贫血模型的优点:将业务逻辑分离了出去,使得系统耦合度降低;对象只用作承载和传输数据。
贫血模型的缺点:只有属性没有行为的对象是没有生命的,显然不符合真正的面向对象编程(OOP)的思想,这样的对象并不是真正的对象,而且由于把业务逻辑分离了到了service层,这就会使得service层显得十分厚重。
二、充血模型
充血模型是指模型中不仅包含了对象的属性,还包含了对象的行为,包括业务逻辑、数据持久化等操作。业务层则只是部分的简答调用逻辑、事务控制、权限控制等。

充血模型的优点:显然充血模型才是真正意义上的面向对象开发,业务层简洁单一。

充血模型的缺点:业务逻辑划分难以明确,什么样的业务放在对象中,什么样的业务放在业务层。模块化开发更难,业务层的人需要深入了解领域层对象的行为方法。

三、两者的对比
1、为什么在日常的开发模式中,贫血模型会受到更广泛的欢迎?
基于贫血模型的传统开发模式,将数据与业务逻辑分离,违反了 OOP 的封装特性,实际上是一种面向过程的编程风格。但是,现在几乎所有的 Web 项目,都是基于这种贫血模型的开发模式,甚至连 Java Spring 框架的官方 demo,都是按照这种开发模式来编写的。

面向过程编程风格有种种弊端,比如,数据和操作分离之后,数据本身的操作就不受限制了。任何代码都可以随意修改数据。既然基于贫血模型的这种传统开发模式是面向过程编程风格的,那它又为什么会被广大程序员所接受呢?关于这个问题,主要是有下面三点原因:
(1)大部分情况下,我们开发的系统业务可能都比较简单,简单到就是基于 SQL 的 CRUD 操作,所以,我们根本不需要动脑子精心设计充血模型,贫血模型就足以应付这种简单业务的开发工作。除此之外,因为业务比较简单,即便我们使用充血模型,那模型本身包含的业务逻辑也并不会很多,设计出来的领域模型也会比较单薄,跟贫血模型差不多,没有太大意义。
(2)充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格。我们从一开始就要设计好针对数据要暴露哪些操作,定义哪些业务逻辑。而不是像贫血模型那样,我们只需要定义数据,之后有什么功能开发需求,我们就在 Service 层定义什么操作,不需要事先做太多设计。
(3)思维已固化,转型有成本。基于贫血模型的传统开发模式经历了这么多年,已经深得人心、习以为常。你随便问一个旁边的大龄同事,基本上他过往参与的所有 Web 项目应该都是基于这个开发模式的,而且也没有出过啥大问题。如果转向用充血模型、领域驱动设计,那势必有一定的学习成本、转型成本。很多人在没有遇到开发痛点的情况下,是不愿意做这件事情的。
2、什么项目应该考虑使用基于充血模型的 DDD 开发模式呢?
相对应的,基于充血模型的 DDD 开发模式,更适合业务复杂的系统开发。比如,包含各种利息计算模型、还款模型等复杂业务的金融系统。

你可能会有一些疑问,这两种开发模式,落实到代码层面,区别不就是一个将业务逻辑放到 Service 类中,一个将业务逻辑放到 Domain 领域模型中吗?为什么基于贫血模型的传统开发模式,就不能应对复杂业务系统的开发?而基于充血模型的 DDD 开发模式就可以呢?

实际上,除了我们能看到的代码层面的区别之外(一个业务逻辑放到 Service 层,一个放到领域模型中),还有一个非常重要的区别,那就是两种不同的开发模式会导致不同的开发流程。基于充血模型的 DDD 开发模式的开发流程,在应对复杂业务系统的开发的时候更加有优势。为什么这么说呢?我们先来回忆一下,我们平时基于贫血模型的传统的开发模式,都是怎么实现一个功能需求的。

不夸张地讲,我们平时的开发,大部分都是 SQL 驱动(SQL-Driven)的开发模式。我们接到一个后端接口的开发需求的时候,就去看接口需要的数据对应到数据库中,需要哪张表或者哪几张表,然后思考如何编写 SQL 语句来获取数据。之后就是定义 Entity、BO、VO,然后模板式地往对应的 Repository、Service、Controller 类中添加代码。

业务逻辑包裹在一个大的 SQL 语句中,而 Service 层可以做的事情很少。SQL 都是针对特定的业务功能编写的,复用性差。当我要开发另一个业务功能的时候,只能重新写个满足新需求的 SQL 语句,这就可能导致各种长得差不多、区别很小的 SQL 语句满天飞。

所以,在这个过程中,很少有人会应用领域模型、OOP 的概念,也很少有代码复用意识。对于简单业务系统来说,这种开发方式问题不大。但对于复杂业务系统的开发来说,这样的开发方式会让代码越来越混乱,最终导致无法维护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值