架构设计之贫血模式与充血模式之我见

Posted ShuSheng007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构设计之贫血模式与充血模式之我见相关的知识,希望对你有一定的参考价值。

概述

由于近年微服务的火爆,竟然带火了领域驱动设计这个老家伙。自从2004年被提出就以来就成为架构师面试中消磨时间的谈资。当面试官实在不知道问啥,但时间还早的时候,领域驱动设计就派上用场了…今天我们要谈的贫血与充血模式也属于其中的概念。这些知识往往不受待见,因为啥呢?因为80%的程序员日常的工作就是完成搬砖的活,往原有的代码"屎山"上继续拉屎,老板关心的是产品,是项目,是利益,你屎山堆的再大,只要遮上一层遮羞布能让客户付钱就行,至于动不动这些指导理论干他毛事。但是另外那20%的人不这么想…

概念

贫血模式与充血模式是描述如何将领域模型转化为程序设计的两种方式。完蛋,有的同学又懵逼了:啥是领域模型?啥是程序设计?问啥是领域对象的还情有可原,问啥是程序设计的那位同学你是几个意思?

例如王二狗要在某东买台mac,然后挑好产品后下了个单,支付时候发现普通会员打95折,金卡会员打9折。

那么在支付这个业务场景下,通过领域分析可以将其转化为领域模型。领域建模各有不同,假设我们这里将支付这一业务场景作为领域边界。那么订单是一个领域对象,会员也可看做是一个领域对象,我们怎么来使用程序实现这个业务逻辑呢?

贫血模型

这个模式本来是被软件大师当反面教材提出来批判和吊打的,但在实际的工程实践中却让人欲罢不能。为什么呢?因为其简单粗暴,而大部分工程实践的代码要求都极低,能运行就行,客户给钱就行,其他都是渣渣。说了半天,啥是贫血模式呢?让我们从实际的例子来干啥一下吧

就以王二狗买mac的业务场景来讨论,我们可以按照如下方式实现程序设计

普通会员一个类 HuiYuan(POJO),一个Service HuiYuanService

public class HuiYuan 
    private double discount;
     //省略getter和setter

具体的业务逻辑均写在HuiYuanService里面,HuiYuan就是一个POJO,不包含任何业务逻辑。例如普通会员平时打95折,618的时候打9折…

金卡会员一个类 JinHuiYuan,一个对应的Service JinHuiYuanService

public class JinHuiYuan 
    private double discount;
    //生日礼物
    private String birthDayGift;
     //省略getter和setter
 

金卡会员同理。 普通会员平时打9折,618的时候打85折,生日当天下单还送一份礼物

支付的具体流程一个Service PayService, 在其中调用HuiYuanServiceJinHuiYuanService 完成下单逻辑。

private HuiYuanService  hyService;
private JinHuiYuanService jhyService;

public void pay()
   if(普通会员)
       hyService.pay();
       return;
   
      if(金卡会员)
       jhyService.pay();
       return;
   
   ...

是不是感觉很熟悉,平时经常这么写呢? 为什么叫贫血模式呢?你看那两个会员类,除了getter 和 setter 其他啥功能都没有,是不是很贫?贫的都尿血!

贫血模式更加的面向过程,领域对象没有反应出其在真实世界的内在联系,在真实世界发生变动时维护起来较为被动

充血模式

充血模式刚好相反,其更贴近与面向对象编程,对程序设计者有较高的要求,其更能反应真实世界中对象的内在联系。

还是上面的例子,使用充血模式怎么设计呢?设计领域对象的时候就在反映真实世界的对象的内在联系了。

  • 会员作为一个领域对象,其有提供折扣的功能
  • 金卡会员也是会员的一种,也具有折扣的功能,只是折扣的力度不同。而且金卡会员还有一些自己的特性。

于是抽象出一个会员接口来

public interface BaseHuiYuan
	void discount();

普通会员一个类

public class HuiYuan implements BaseHuiYuan
  private double discount;
  public void discount()
    // 普通会员平时打95折,618的时候打9折...
  

金卡会员一个类

public class JinHuiYuan implements BaseHuiYuan
  ...

最后是业务调用方 PayService

//判断用户是什么会员
public void pay(BaseHuiYuan hy)
       hy.discount()

明白为什么叫充血模式了吧,每个领域对象不仅包含了自己所拥有的数据,也包含了本身具备的动作。就好比一个人有姓名、性别等属性,也有吃饭、学习等动作。如果你只有姓名和性别等属性,而自身没有这些动作,那不就成了提线木偶了吗? 提线那个人(Service)让你睡觉你睡觉,让你学习你学习…

总结

那充血模式与贫血模式哪个好呢? 其实吧这又是一个争论多年的话题。充血模式在理论上非常完美和优雅,但在工程实践中不尽如人意,一是因为大千世界过于复杂导致对程序设计者提出了非常高的要求,二是因为实际工程以解决问题为导向,不在乎代码"屎山"。个人意见还是因地制宜,采各家之长,不要把自己局限在某个模式之下,白猫黑猫抓住老鼠就是好毛!

以上是关于架构设计之贫血模式与充血模式之我见的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之美(c++)-笔记-11-基于贫血模型的MVC架构

设计模式简单工厂之我见

设计模式之美——DDD充血模式

领域驱动设计之我见-实现模式

设计模式之我见

DDD领域驱动设计:贫血模型和充血模型详解