原来我们一直写的是违反面向对象编程风格的代码
admin
2024-04-07 21:39:08
0

众所周知,很多业务系统都是基于 MVC 三层架构来开发的,虽然这种开发模式已经成为标准的 Web 项目的开发模式,但它却违反了面向对象编程风格,是一种彻彻底底的面向过程的编程风格,因此被有些人称为反模式(anti-pattern)。特别是领域驱动设计(Domain Driven Design,简称 DDD)盛行之后,这种基于贫血模型的传统的开发模式就更加被人诟病,而基于充血模型的 DDD 开发模式越来越被人提倡。

文章目录

  • 什么是贫血模型?
  • 什么是充血模型?
  • 什么是领域驱动设计(DDD)?
  • 基于贫血模型的传统开发模式既然违反 OOP,那又为什么如此流行?
  • 什么情况下我们应该考虑使用基于充血模型的 DDD 开发模式?

什么是贫血模型?

先回顾一下,什么是 MVC 三层架构?

MVC 三层架构中的 M 表示 Model,V 表示 View,C 表示 Controller。它将整个项目分为三层:展示层、逻辑层、数据层。MVC 三层开发架构是一个比较笼统的分层方式,落实到具体的开发层面,很多项目也并不会 100% 遵从 MVC 固定的分层方式,而是会根据具体的项目需求,做适当的调整。比如,现在很多 Web 或者 App 项目都是前后端分离的,后端负责暴露接口给前端调用。这种情况下,我们一般就将后端项目分为 Repository 层、Service 层、Controller 层。其中,Repository 层负责数据访问,Service 层负责业务逻辑,Controller 层负责暴露接口。当然,这只是其中一种分层和命名方式。不同的项目、不同的团队,可能会对此有所调整。不过,万变不离其宗,只要是依赖数据库开发的 Web 项目,基本的分层思路都大差不差。

实际上,我们一直都在用贫血模型做开发,只是自己不知道而已。其实不夸张地讲,目前几乎所有的业务后端系统,都是基于贫血模型的。

例如,我们平时开发 Web 后端项目的时候,UserEntity 和 UserRepository 组成了数据访问层,UserBo 和 UserService 组成了业务逻辑层,UserVo 和 UserController 在这里属于接口层,基本上都是这么组织代码的。

UserBo 是一个纯粹的数据结构,只包含数据不包含任何业务逻辑,业务逻辑集中在 UserService 中,我们通过 UserService 来操作 UserBo。换句话说,Service 层的数据和业务逻辑,被分割为 BO 和 Service 两个类中。像 UserBo 这样,只包含数据,不包含业务逻辑的类,就叫作贫血模型(Anemic Domain Model)。同理,UserEntity、UserVo 都是基于贫血模型设计的,这种贫血模型将数据与操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。

什么是充血模型?

在贫血模型中,数据和业务逻辑被分割到不同的类中。充血模型(Rich Domain Model)正好相反,数据和对应的业务逻辑被封装到同一个类中。因此,这种充血模型满足面向对象的封装特性,是典型的面向对象编程风格。

什么是领域驱动设计(DDD)?

领域驱动设计(Domain Driven Design,简称 DDD),主要是用来指导如何解耦业务系统,划分业务模块,定义业务领域模型及其交互。

我们知道,除了监控、调用链追踪、API 网关等服务治理系统的开发之外,微服务还有另外一个更加重要的工作,那就是针对公司的业务,合理地做微服务拆分。而领域驱动设计恰好就是用来指导划分服务的。所以,微服务加速了领域驱动设计的盛行。

做好领域驱动设计的关键是,看你对自己所做业务的熟悉程度,而并不是对领域驱动设计这个概念本身的掌握程度。即便你对领域驱动搞得再清楚,但是对业务不熟悉,也并不一定能做出合理的领域设计。所以,不要把领域驱动设计当银弹,不要花太多的时间去过度地研究它。

实际上,基于充血模型的 DDD 开发模式实现的代码,也是按照 MVC 三层架构分层的。Controller 层还是负责暴露接口,Repository 层还是负责数据存取,Service 层负责核心业务逻辑。它跟基于贫血模型的传统开发模式的区别主要在 Service 层。

在基于贫血模型的传统开发模式中,Service 层包含 Service 类和 BO 类两部分,BO 是贫血模型,只包含数据,不包含具体的业务逻辑。业务逻辑集中在 Service 类中。在基于充血模型的 DDD 开发模式中,Service 层包含 Service 类和 Domain 类两部分。Domain 就相当于贫血模型中的 BO。不过,Domain 与 BO 的区别在于它是基于充血模型开发的,既包含数据,也包含业务逻辑。而 Service 类变得非常单薄。总结一下的话就是,基于贫血模型的传统的开发模式,重 Service 轻 BO;基于充血模型的 DDD 开发模式,轻 Service 重 Domain。

基于贫血模型的传统开发模式既然违反 OOP,那又为什么如此流行?

基于贫血模型的传统开发模式,将数据与业务逻辑分离,违反了 OOP 的封装特性,实际上是一种面向过程的编程风格。但是,现在几乎所有的 Web 项目,都是基于这种贫血模型的开发模式,甚至连 Java Spring 框架的官方 demo,都是按照这种开发模式来编写的。

前面讲过,面向过程编程风格有种种弊端,比如,数据和操作分离之后,数据本身的操作就不受限制了。任何代码都可以随意修改数据。既然基于贫血模型的这种传统开发模式是面向过程编程风格的,那它又为什么会被广大程序员所接受呢?关于这个问题,大概总结了下面三点原因:

  • 第一点原因是,大部分情况下,我们开发的系统业务可能都比较简单,简单到就是基于 SQL 的 CRUD 操作,所以,我们根本不需要动脑子精心设计充血模型,贫血模型就足以应付这种简单业务的开发工作。除此之外,因为业务比较简单,即便我们使用充血模型,那模型本身包含的业务逻辑也并不会很多,设计出来的领域模型也会比较单薄,跟贫血模型差不多,没有太大意义。
  • 第二点原因是,充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格,我们从一开始就要设计好针对数据要暴露哪些操作,定义哪些业务逻辑。而不是像贫血模型那样,我们只需要定义数据,之后有什么功能开发需求我们就在 Service 层定义什么操作,不需要事先做太多设计。
  • 第三点原因是,思维已固化,转型有成本。基于贫血模型的传统开发模式经历了这么多年,已经深得人心、习以为常。你随便问一个旁边的大龄同事,基本上他过往参与的所有 Web 项目应该都是基于这个开发模式的,而且也没有出过啥大问题。如果转向用充血模型、领域驱动设计,那势必有一定的学习成本、转型成本。很多人在没有遇到开发痛点的情况下,是不愿意做这件事情的。

什么情况下我们应该考虑使用基于充血模型的 DDD 开发模式?

既然基于贫血模型的开发模式已经成为了一种约定俗成的开发习惯,那什么样的项目应该考虑使用基于充血模型的 DDD 开发模式呢?

基于贫血模型的传统的开发模式,比较适合业务比较简单的系统开发。相对应的,基于充血模型的 DDD 开发模式,更适合业务复杂的系统开发,比如,包含各种利息计算模型、还款模型等复杂业务的金融系统。

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

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

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

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

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

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

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


笔记总结自极客时间《设计模式之美》

相关内容

热门资讯

安卓系统音乐软件推荐,五大热门... 你有没有发现,手机里音乐软件那么多,挑一款适合自己的真心不容易啊!安卓系统上的音乐软件更是五花八门,...
安卓系统刷三星系统,轻松刷入最... 你有没有想过,你的安卓手机其实可以变身成三星的旗舰机呢?没错,就是那种屏幕大、性能强、系统流畅的旗舰...
塞班系统可以转为安卓,跨越时代... 你知道吗?现在科技的发展真是让人眼花缭乱,连我们曾经熟悉的塞班系统也能华丽转身,变成安卓系统呢!是不...
安卓系统如何录像剪辑,录像剪辑... 亲爱的手机控们,你是否有过这样的经历:在某个瞬间,你捕捉到了一段令人难忘的画面,却因为没来得及记录而...
安卓系统强行提高配置,配置提升... 最近你的安卓手机是不是感觉有点儿“发烧”了?没错,就是那种配置突然“升级”的感觉。你是不是也觉得,手...
安卓系统能做设计吗,探索安卓系... 你有没有想过,安卓系统竟然也能做设计?是的,你没听错,这个我们日常使用的手机操作系统,竟然也能成为设...
安卓系统几年后使用,探索多年使... 你有没有想过,那些陪伴我们多年的安卓手机,它们现在过得怎么样了呢?安卓系统,这个曾经让我们爱恨交加的...
平板安卓苹果双系统,安卓与苹果... 你有没有想过,拥有一台既能运行安卓系统,又能使用苹果系统的平板电脑,那该是多么酷炫的事情啊!想象一边...
嘉和病历系统安卓,便捷医疗信息... 你有没有听说过嘉和病历系统安卓版?这可是医疗行业的一大神器呢!想象医生们拿着手机就能轻松管理病历,患...
安卓10更改系统号,揭秘系统编... 你知道吗?最近安卓系统又来了一次大更新,安卓10正式上线了!这次更新可是带来了不少新功能,其中最引人...
小米墨水屏 安卓系统,融合科技... 你知道吗?在科技日新月异的今天,电子阅读器市场也迎来了新的活力。而小米,这个我们熟悉的品牌,最近推出...
系统软件最少的安卓系统,基于最... 你有没有想过,手机系统就像是我们生活的操作系统,有时候太复杂了,让人感觉头都大了。今天,我要给你介绍...
安卓系统关闭应用推荐,安卓系统... 你有没有发现,手机里的安卓系统最近有点儿“小情绪”,总是给你推荐一些你根本不感兴趣的应用?别急,今天...
车载安卓系统如何用,智能驾驶体... 你有没有想过,你的车载安卓系统其实是个隐藏的宝库呢?没错,就是那个你每天开车时几乎不离手的那个屏幕,...
安卓系统更新如何取消,```p... 你有没有遇到过这种情况:安卓手机的系统更新推送得让人有点头疼,有时候更新后的系统还各种不适应。别急,...
安卓系统源码修改练习,从零开始... 亲爱的技术爱好者,你是否曾梦想过深入安卓系统的内核,亲手修改源码,让手机变得更加个性化?那就让我们一...
安卓考勤系统论文,基于安卓平台... 你有没有想过,每天打卡上班,是不是也能变得有趣起来呢?没错,就是那个我们每天都要面对的安卓考勤系统。...
安卓系统哪家流畅度,安卓系统流... 手机里的安卓系统,就像是每个人的小世界,各有各的风采。但说到流畅度,这可是大家最关心的问题了。今天,...
安卓开不了定位系统,安卓设备定... 最近是不是发现你的安卓手机定位系统突然罢工了?别急,别慌,今天就来给你详细解析一下这个问题,让你轻松...
安卓系统怎么设置airpod,... 你有没有发现,自从AirPods问世以来,它就成为了科技界的宠儿?这款无线耳机不仅音质出众,而且连接...