Java微服务构建:打造健壮订单模型的完整指南

2023-10-31 18:28

本文主要是介绍Java微服务构建:打造健壮订单模型的完整指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java微服务构建一个健壮的订单模型(业务,规划,设计与实现)

在设计领域业务模型时,我们通常会追求理论完美,而忽略实践的脆弱性。尽管我们没有贬低领域建模的意图,但事实上,在电商技术发展多年之后,某些系统模型仍然缺乏弹性。本文将结合多年电商交易经验,分享一些个人对设计思路的见解,与大家共同学习、进步。

探究交易的本质:合同签订和履约的全过程

交易是指买卖双方在签订合同并履约的过程中完成的一系列活动。合同签订是正向交易的职责,而履约则包括物流、仓储和发货等服务。合同包含的内容非常丰富,比如卖家售卖什么产品、提供哪些服务、如何履约或违约的赔偿方式、如何维权等。如图1所示,当然图中缺少了维权的部分。如果买家对产品不满意或发现质量问题,可以根据合同中的条款进行退款、换货等。这些条款可能包含一些隐含的要求,例如电商法中的规定。

28c6228b882c30d2cbb858655b2087f4.jpeg


(图1)

在电子商务的交易中一般是人、产品的进行的一次互通的行为。从维基百科的定义来看交易其实包含物品或者服务,可能你既提供产品又提供服务,也可能你只卖服务,这个时候就没有产品。产品也可能不是真实存在的物品,它也可能是一种虚拟的商品,比如虚拟的货币。我先分析一般情况下交易设计的模型。

订单模型

一个实体模型就是一个独立的事物。每个实体都拥有一个唯一的标识符,可以将它的个体性和所有其他类型相同或者不同的实体区分开。许多时候,也许应该说绝大多数时候,实体是可变的。也就是说,它的状态会随着时间发生变化。不过,一个实体不一定必须是可变的,它也可能是不可变的。

在设计的时候关于实体和值对象的区分有时候是比较困难的,不同人可能对实体的理解不一样。比如对订单条目OrderItem是实体还是值对象?有的人认为是实体有的人认为是值对象。订单的话有订单id或者订单号来做唯一标识,这个共识会比较强,那么条目orderItemId是不是订单条目的唯一标识呢?在考虑这个是否是唯一标识的是不是有意义的下,我们可以跟值对象做对比,实体区别于值对象的最大原因是,值对象的值是不可变的,比如我们的收货人信息Receiver,在下单用户选择地址的那一刻就已经确定下来了,在订单域他就是一个地址信息,他的属性在订单的生命周期中不会改变,它只是用来发货的,它也没有唯一标识,所以他是一个值对象。一个订单可能有多个条目,每个条目是可以单独发货,在下单待支付的时候也可以对条目的商品进行改价,收货维权的时候买家或者商家可以选择某个商品进行退款,所以他在订单生命周期中会随着时间的变化而变化,所以它是一个实体,他的唯一标识就是orderItemId。

5945c1602984823fe084bfe8b4d75af3.jpeg

订单关系

订单这个聚合根我们再熟悉不过了,在很多电商领域都会提到这个聚合根,如图1大体的我们一般会得出这样的一个关联关系,这个关系有点单薄。虽然他可以体现出订单这个聚合的大体依赖关系,并且可以表达80%的场景,但是不能比较好的体现销售订单和采购订单的关系。销售订单主要是站在买家的角度阐明买家下单,采购订单主要是站在商家的角度向供应商下单。所以至少我们在订单中需要有一个值对象来标识这个关系,对应的条目其实也有这一层的关系。

ef99e7601570cf3a0836eed1bd32fb28.jpeg

订单条款

一般的电商交易都会有一些显示或者隐私的条款的,隐私的比如物流条款选择的物流配送方式,是自提还是快递或者无需物流,物流的显示条款可能有是否支持运费险。在维权方面还有一些隐性或者显性的条款,比如是否支持7天无理由退货。还要一些活动,比如定金预售,我们在商品下单的时候就会给用户提示下了定金是不支持退款的,我们这边的订单条款主要考虑的是显示的条款,隐私条例一般是电商法需要支持的,是一种默认的条款。

但是很遗憾,这些条款信息在我做过的交易里是没有很好的体现(因为历史的债务),甚至有些条款都是没有落库的,有些条款是通过扩展字段存储在订单扩展字段或者条目的扩展字段中。现在我们交易系统在很大程度上解决扩展性问题,都是通过扩展字段来承载,所以有了很多打标的接口,这样处理当然在性能上是有很大的好处,比如解决了性能问题,但是在复杂的业务系统中,其实就隐藏了一部分业务逻辑,在领域设计中是不被允许的,所以在解决性能问题的情况下我们可能需要平衡一些业务。大量的打标服务从而导致扩展字段的急速膨胀,最终解决的办法就是不断的扩充extra字段的长度。

08c8ab387f3316b90b1709b6a73ddd41.jpeg

订单调整

我们在下单支付等过程经常的会对订单进行一些调整,比如我们会对待支付的订单进行改价,这个一般的我们需要一个调整单,显示的记录这个调整。广义上来讲,我们订单的调整还包含一些费用,比如附加费、额外费用,商品或者运费的均摊,这些数据还比较复杂,一般的是作用在订单条目的,如果要在订单条目存储会比较复杂,因为包含的内容还比较多,比如调整价格,原价,调整原因,调整时间等等。所以这些调整信息比较适合单独拎出来存储。调整单的设计在ERP系统比较常见,比如我们在算出入库的时候,在月末结算不均衡的时候会手动入一个入库调整单。这里讲的订单调整不是ERP的调整单,它是针对交易的计算价格的时候,对商品价格的一些调整。

d0247e65021c1498c7267c8a00dc8574.jpeg

一般的,订单调整是指在订单创建后,由于各种原因需要对订单的价格、数量、物品等进行修改的过程。在实际业务中,常见的订单调整场景包括满减活动、优惠券使用、商品退换货等。以满减活动为例,当满足活动条件后,系统会自动计算出优惠的金额并减免相应的金额,然后将修改后的订单金额保存在数据库中。此时,订单状态也会发生相应的变化,例如待支付的订单状态会变成待发货、待收货的订单状态也会相应地发生改变。在调整过程中,需要对订单相关的数据进行验证和更新,保证数据的准确性和一致性,同时还需要对用户进行提示和通知,以避免产生误解和纠纷。

1b65d3da3c5a6fa756296916f1a7dd20.jpeg

订单状态

订单的状态是随着时间推移而发生变化的,订单的状态变化可以通过不同的事件来触发。订单的状态通常包括:创建、待支付、已支付、待发货、已发货、待收货、已收货等。

当买家下单后,订单状态为“创建”,此时卖家需要对订单进行确认并进行库存锁定等操作。如果卖家确认订单信息无误,则将订单状态变更为“待支付”;否则将订单状态变更为“取消”。

当买家完成支付后,订单状态变更为“已支付”。此时,卖家可以开始准备商品进行发货,或者进行拣货、分拣等前置工作。在准备好商品后,订单状态变更为“待发货”。

当卖家将商品发出后,订单状态变更为“已发货”。此时,买家可以开始关注物流信息,并等待商品的到达。如果商品未按时到达或者出现其他问题,买家可以通过平台提供的维权服务进行投诉。

当商品到达买家手中时,订单状态变更为“待收货”。买家需要在收到商品后进行确认,如果确认收货,则订单状态变更为“已收货”,交易完成。如果买家在一定时间内未确认收货,则订单状态会自动变更为“已完成”。

在订单状态变更的过程中,可能会存在一些意外情况,例如买家取消订单、买家申请退货等,这些事件会触发订单状态的相应变化,以确保交易的公正、合法和安全。

订单状态记录着订单生命周期,其实还是比较核心并且复杂的一个实体。不同的订单类型的订单状态流转不一样,这个需要进行一个统一的设计,一般的话我们会考虑用状态机来实现。交易中的订单状态是可以枚举的,一般的我们会把订单状态设计成一个枚举类,但是订单状态其实承载了很多操作和控制状态流转的行为,所以它其实应该是有自己的唯一标识的实体。

73b32d64183340d48f3c63c9763b01ab.jpeg

这篇关于Java微服务构建:打造健壮订单模型的完整指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/317254

相关文章

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

Java CompletableFuture如何实现超时功能

《JavaCompletableFuture如何实现超时功能》:本文主要介绍实现超时功能的基本思路以及CompletableFuture(之后简称CF)是如何通过代码实现超时功能的,需要的... 目录基本思路CompletableFuture 的实现1. 基本实现流程2. 静态条件分析3. 内存泄露 bug

Java中Object类的常用方法小结

《Java中Object类的常用方法小结》JavaObject类是所有类的父类,位于java.lang包中,本文为大家整理了一些Object类的常用方法,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. public boolean equals(Object obj)2. public int ha

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插