「java充血模型」java充血模型和贫血模型

博主:adminadmin 2022-11-25 16:36:09 58

本篇文章给大家谈谈java充血模型,以及java充血模型和贫血模型对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

java为什么只用贫血模式

充血模式和贫血模式

贫血模型:是指领域对象里只有get和set方法,或者包含少量的CRUD方法,所有的业务逻辑都不包含在内而是放在Business Logic层。

优点是系统的层次结构清楚,各层之间单向依赖,Client-(Business Facade)-Business Logic-Data Access(ADO.NET)。当然Business Logic是依赖Domain Object的。似乎现在流行的架构就是这样,当然层次还可以细分。

该模型的缺点是不够面向对象,领域对象只是作为保存状态或者传递状态使用,所以就说只有数据没有行为的对象不是真正的对象。在Business Logic里面处理所有的业务逻辑,在POEAA(企业应用架构模式)一书中被称为Transaction Script模式。

充血模型:层次结构和上面的差不多,不过大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client-(Business Facade)-Business Logic-Domain Object-Data Access。

它的优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。

缺点是如何划分业务逻辑,什么样的逻辑应该放在Domain Object中,什么样的业务逻辑应该放在Business Logic中,这是很含糊的。即使划分好了业务逻辑,由于分散在Business Logic和Domain Object层中,不能更好的分模块开发。熟悉业务逻辑的开发人员需要渗透到Domain Logic中去,而在Domian Logic又包含了持久化,对于开发者来说这十分混乱。 其次,因为Business Logic要控制事务并且为上层提供一个统一的服务调用入口点,它就必须把在Domain Logic里实现的业务逻辑全部重新包装一遍,完全属于重复劳动。

如果技术能够支持充血模型,那当然是最完美的解决方案。不过现在的.NET框架并没有ORM工具(不算上开源的NHibernate,Castle之类),没有ORM就没有透明的持久化支持,在Domain Object层会对Data Access层构成依赖,如果脱离了Data Access层,Domain Object的业务逻辑就无法进行单元测试,这也是很致命的。如果有像Spring的动态注入和Hibernate的透明持久化支持,那么充血模型还是能够实现的。

选择了.NET平台开发,就是选择了开发高效、功能强大应用简单,最适合的模型就是贫血模型,或表数据入口,既有编译器和语言平台很好的支持,也符合微软提倡的开发模式。如果跟潮流在项目中使用充血模型,现有的ORM工具都很复杂难用,光是维护大量的映射文件都成问题。说贫血不够OO,它的Domain Object不够丰富,能把项目做好了,有一定的扩展能力和伸缩行就行了,也不一定要讲究优雅的面向对象。正如SOA,讲究松耦合、高内聚,服务端给客户端提供的服务,也就是一系列的方法调用加上DTO而已,不管服务的内部是不是面向对象的实现,至少它暴露出来的是过程式的服务。

JavaBean和EJB的区别

首先,EJB是指运行在EJB容器中的JavaBean。Tomcat是Web容器的参考实现。一个完整的JavaEE服务器应该包括Web容器和EJB容器。

其次,Web容器中无法运行EJB,同时所有的JavaBean都是在服务器端运行的。如果有在客户端的话,就变成C/S结构了。

目前来说除非需要分布式处理,不然基本上不需要考虑EJB。Spring能帮你处理好除分布计算之外的一切。

用JavaScript来进行服务器调用的话,属于Ajax的范围了。

至于购物车。一般来说有几种方法,一种是EJB中的有状态SessionBean。一种是使用HttpSession保存。还有就是自己建设一个对象池来处理。

JavaBean是领域模型的具体化类,保存了信息和业务。只有set、get方法的JavaBean是失血模型。现在来说一般多少不太欢迎这种东西。把本属于领域对象的业务逻辑都丢掉了。

实际上现在的JavaEE系统分这么几个层。

表现层(Struts、JSF等)+应用层(处理业务,可以是JavaBean也可以是EJB)+持久层(JDBC、Hibernate)。

不要在Struts的Action类中写业务代码,那是反模式。不然日后需要修改的时候很麻烦的。Action中只有流程指向和对应用层的调用。

领域模型分实体、值对象和服务三部分。一般实体里写业务代码、值对象显示、服务提供相对独立的业务。失血模型指一个对象中除了get和set方法外没有任何方法的类。现在不太推荐。addobject(objece **),delete(object **)...之类的方法就是业务。这些业务封进去后,失血模型就变成了缺血模型。充血模型把持久化服务等也包了,所以也不是很号。缺血比较推荐。

登录等流程其实是服务。推荐你去看看DDD设计的书也就是《领域驱动设计》。

DDD碎片记录 05. 充血模型的优点

将领域模型的原貌直接转换为程序中领域对象的设计,这时,各种业务操作就不再在服务中实现了,而是在领域对象中实现,如【订单充血模型设计图】所示,在程序设计时,既有父类的订单,又有子类实物订单,虚拟订单。并且,在领域对象中的方法,也同样保留到了程序设计的实体对象中,这样通过继承,虽然实物订单,虚拟订单都有订单履约,但实物订单的履约与虚拟订单的履约是不一样的。虽然在充血模型中也有订单service,里面也有订单履约方法,但是充血模型的service只干一件特别简单的事,那就是在接收到用户的请求后,就直接去调用实体对象中的相应方法,其他的什么都不干。这样订单service不需要去关注现在调用的是实物订单的订单履约方法,还是虚拟订单的订单履约方法,只需要订单履约就行了。如果当前拿到的是实物订单就执行实物订单的订单履约方法,如果拿到的是虚拟订单就执行虚拟订单的订单履约方法。当需求增加一个服务订单时,就只需要增加一个服务订单的子类,重载会员订单履约方法,而订单service不需要做任何修改,变更的维护成本就大大降低了。

迄今为止最完整的DDD实践

作者:章磊(章三) 阿里飞猪技术团队

对于一个架构师来说,在软件开发中如何降低系统复杂度是一个永恒的挑战。

领域(战略):业务范围,范围就是边界。

子领域:领域可大可小,我们将一个领域进行拆解形成子领域,子领域还可以进行拆解。当一个领域太大的时候需要进行细化拆解。

模型(战术):基于某个业务领域识别出这个业务领域的聚合,聚合根,界限上下文,实体,值对象。

决定产品和公司核心竞争力的子域是核心域,它是业务成功的主要因素和公司的核心竞争力。 直接对业务产生价值 。

没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域。例如,权限,登陆等等。 间接对业务产生价值 。

支撑其他领域业务,具有企业特性,但不具有通用性。 间接对业务产生价值 。

一个业务一定有他最重要的部分,在日常做业务判断和需求优先级判断的时候可以基于这个划分来做决策。例如:一个交易相关的需求和一个配置相关的需求排优先级,很明显交易是核心域,规则是支持域。同样我们认为是支撑域或者通用域的在其他公司可能是核心域,例如权限对于我们来说是通用域,但是对于专业做权限系统的公司,这个是核心域。

业务的边界的划分,这个边界可以是一个领域或者多个领域的集合。复杂业务需要多个域编排完成一个复杂业务流程。限界上下文可以作为微服务划分的方法。其本质还是高内聚低耦合,只是限界上下文只是站在更高的层面来进行划分。如何进行划分,我的方法是一个界限上下文必须支持一个完整的业务流程,保证这个业务流程所涉及的领域都在一个限界上下文中。

定义: 实体有唯一的标识,有生命周期且具有延续性。例如一个交易订单,从创建订单我们会给他一个订单编号并且是唯一的这就是 实体唯一标识 。同时订单实体会从创建,支付,发货等过程最终走到终态这就是 实体的生命周期 。订单实体在这个过程中属性发生了变化,但订单还是那个订单,不会因为属性的变化而变化,这就是 实体的延续性 。

实体的业务形态: 实体能够反映业务的真实形态,实体是从用例提取出来的。领域模型中的实体是多个属性、操作或行为的载体。

实体的代码形态: 我们要保证实体代码形态与业务形态的一致性。那么实体的代码应该也有属性和行为,也就是我们说的充血模型,但实际情况下我们使用的是贫血模型。贫血模型缺点是业务逻辑分散,更像数据库模型,充血模型能够反映业务,但过重依赖数据库操作,而且复杂场景下需要编排领域服务,会导致事务过长,影响性能。所以我们使用充血模型,但行为里面只涉及业务逻辑的内存操作。

实体的运行形态: 实体有唯一ID,当我们在流程中对实体属性进行修改,但ID不会变,实体还是那个实体。

实体的数据库形态: 实体在映射数据库模型时,一般是一对一,也有一对多的情况。

值对象的运行形态: 值对象创建后就不允许修改了,只能用另外一个值对象来整体替换。当我们修改地址时,从页面传入一个新的地址对象替换调用person对象的地址即可。如果我们把address设计成实体,必然存在ID,那么我们需要从页面传入的地址对象的ID与person里面的地址对像的ID进行比较,如果相同就更新,如果不同先删除数据库在新增数据。

值对象的数据库形态: 有两种方式嵌入式和序列化大对象。

案例1:以属性嵌入的方式形成的人员实体对象,地址值对象直接以属性值嵌入人员实体中。

当我们只有一个地址的时候使用嵌入式比较好,如果多个地址必须有序列化大对象。同时可以支持搜索。

案例2:以序列化大对象的方式形成的人员实体对象,地址值对象被序列化成大对象 Json 串后,嵌入人员实体中。

支持多个地址存储,不支持搜索。

值对象的优势和局限:

1.简化数据库设计,提升数据库操作的性能(多表新增和修改,关联表查询)

2.虽然简化数据库设计,但是领域模型还是可以表达业务

3.序列化的方式会使搜索实现困难(通过搜索引擎可以解决)

多个实体和值对象组成的我们叫聚合,聚合的内部一定的高内聚。这个聚合里面一定有一个实体是聚合根。

聚合与领域的关系:聚合也是范围的划分,领域也是范围的划分。领域与聚合可以是一对一,也可以是一对多的关系

聚合根的作用是保证内部的实体的一致性,对外只需要对聚合根进行操作。

领域包含限界上下文,限界上下文包含子域,子域包含聚合,聚合包含实体和值对象

除了领域专家,事件风暴的其他参与者可以是DDD专家、架构师、产品经理、项目经理、开发人员和测试人员等项目团队成员

一面墙和一支笔。

实体执行命令产生事件。

通过业务场景和用例找出实体,命令,事件。

领域建模时,我们会根据场景分析过程中产生的领域对象,比如命令、事件等之间关系,找出产生命令的实体,分析实体之间的依赖关系组成聚合,为聚合划定限界上下文,建立领域模型以及模型之间的依赖。领域模型利用限界上下文向上可以指导微服务设计,通过聚合向下可以指导聚合根、实体和值对象的设计。

需求:我们需要把系统自动化失败转人工订单自动分配给小二,避免人工挑单和抢单,通过自动分配提升整体履约处理效率。

沟通的过程就是推导和验证模型的过程,最后进行域的划分:

穷举所有场景,重新验证模型是否可以覆盖所有场景。

每一层都定义了相应的接口主要目的是规范代码:

application:CRQS模式,ApplicationCmdService是command,ApplicationQueryService是query

service:是领域服务规范,其中定义了DomainService,应用系统需要继承它。

model:是聚合根,实体,值对象的规范。

repository

event:事件处理

exception:定义了不同层用的异常

域服务,聚合根,值对象,领域参数,仓库定义

所有技术代码在这一层。mybatis,redis,mq,job,opensearch代码都在这里实现,domain通过依赖倒置不依赖这些技术代码和JAR。

对外提供服务

内外都要用的共享对象

充血模型VS贫血模型:

规范大于技巧:DDD架构可以避免引入一些其他概念,系统只有域,域服务,聚合根,实体,值对象,事件来构建系统。

聚合根的reconProcess的方法的业务逻辑被reconHandler和reconRiskHandler处理,必然这些handler要访问聚合根里面的实体的属性,那么逻辑就会散落。修改后:

没有引入其他概念,都是在聚合根里面组织实体完成具体业务逻辑,去掉了handler这种技术语言。

修改了mapstruct生成转换代码的源码,修改后生成的代码:

当属性被改变后就转换到po中,这样就可以实现修改后的字段更新。修改后的mapstruct代码地址:git@gitlab.alibaba-inc.com:flight-agent/mapstruct.git

DDD领域驱动设计-DDD概览

# DDD概览

## 启迪

领域可以理解为业务,领域专家就是对业务很了解的人。

限界上下文也就是微服务的边界,也可以理解为微服务,一个限界上下文=一个微服务。

个人理解领域驱动设计就是微服务驱动设计,从战略上先进行微服务的划分,从战术上针对某个微服务进行领域模型的设计也就是业务模型的设计。

领域模型包括:

- 实体

- 值对象

- 聚合

- 领域服务

- 领域事件

- 资源库

- 应用服务

## 什么是领域驱动设计?

理解领域驱动设计是什么之前,我们先来理解下什么是领域?

领域可以理解为业务,领域专家就是对业务很了解的人。

领域驱动设计的核心就是和最了解业务的人也就是领域专家一起通过领域建模的方式去设计我们的软件程序。

- 那么领域如何驱动设计?或者说业务如何驱动设计?

传统开发过程我们都是基于面向数据开发,拿到产品原型脑海里想着都是应该创建哪些表和哪些字段才能满足需求。

而领域驱动设计开发过程是让我们基于面向业务开发、面向领域模型开发。

领域模型的核心是通过承载和保存领域知识,并通过模型与代码的映射将这些领域知识保存在程序代码中,

在传统开发中,当业务被转换为一张张数据表时,丢失最多的就是领域知识(领域知识也就是我们在模型中定义的一些业务逻辑行为)。

面向领域模型开发的优点:

- 存储方便,统一使用JSON进行存储。

例:

订单领域包含基础信息、商品信息、金额信息、支付信息等包含订单全生命周期的子域,

对于传统面向数据的开发模式我们需要创建N张表进行存储订单的信息,但是面向领域开发时我们

可以通过利用nosql数据库(mongo、es等)进行保存整个订单域的信息,提高查询、更新效率,简化代码

- 复用性高,引用某个领域模型,就可以拥有该领域模型的所有行为。

例:

基于微服务架构下,某个电商应用需要一个判断某个订单是否是在线支付订单的逻辑时,

对于传统的开发模式我们需要调用订单中心的服务查询订单信息,然后写一个判断是否在线支付订单的方法。

如果有多个应用都需要这个逻辑时,每个应该都需要重复写相同的方法。

但面向领域开发时,只需要引用订单中心的jar包,然后统一调用订单领域内的方法即可。

这样就实现了业务的高内聚

## DDD可以做什么

DDD主要分为两个部分,战略设计与战术设计

- 战略设计

- 围绕微服务拆分

- 战术设计

- 微服务内部设计

## DDD怎么做

- 战略设计

- 和领域专家一起通过(过往经验、事物联系、事件风暴等)划分【限界上下文】

限界上下文也就是微服务的边界,也可以理解为微服务。

一个限界上下文=一个微服务

- 战术设计

- 开发人员通过(领域模型)保存【领域知识】

领域知识也就是事物(角色)、行为(规则)和关系

## DDD领域模型

领域模型包含什么?

- 实体

具有唯一标识,包含着业务知识的【充血模型】对象,用于对唯一性事物进行建模。

例:

```

public class Order {

private long orderId;

private OrderAmount amount;

private List item;

}

```

- 值对象

生成后即不可变对象,通常作为实体的属性,用于描述领域中的事物的某种特征。

例:

```

public class OrderItem {

private long orderId;

private String productCode;

private String productName;

}

```

- 聚合

将实体和值对象在一致性边界之内组成聚合,使用聚合划分微服务(限界上下文)内部的边界

- 领域服务

分担实体的功能,承接部分业务逻辑,做一些实体不变处理的业务流程。不是必须的

主要承接内部领域服务调用和外部微服务调用,及一些聚合业务逻辑处理。

例:

```

@Service

public class ShoppingcartDomainService {

private final ShoppingcartRepository shoppingcartRepository;

private final ProductFacade productFacade;

private final UserFacade userFacade;

private final PromotionFacade promotionFacade;

// 1.查询购物车信息

ShoppingcartDO entity = shoppingcartRepository.loadShoppingcart(userId);

// 2.调用【用户中心】服务查询用户信息

User user = userFacade.getUser(userId);

// 3.调用【商品中心】服务查询商品信息

Product product = productFacade.getProduct(productCode);

// 4.调用【活动中心】服务查询活动信息

Promotion promotion = promotionFacade.getPromotionByProductCode(productCode);

// 5.创建购物车实体

Shoppingcart shoppingcart = new Shoppingcart(entity.getId, user, product, promotion);

// 6.购物车按活动分组

shoppingcart.groupby4Promotion();

}

```

- 领域事件

表示领域中发生的事情,通过领域事件可以实现本地微服务(限界上下文)内的信息同步,同时也可以实现对外部系统的解耦

- 资源库

保存聚合的地方,将聚合实例存放在资源库(Repository)中,之后再通过该资源库来获取相同的实例。

- 应用服务

应用服务负责流程编排,它将要实现的功能委托给一个或多个领域服务来实现,

本身只负责处理业务用例的执行顺序以及结果的拼装同时也可以在应用服务做些权限验证等工作。

![](images/application-service.png)

关于java充血模型和java充血模型和贫血模型的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

发布于:2022-11-25,除非注明,否则均为首码项目网原创文章,转载请注明出处。