如何一步一步用DDD设计一个电商网站(十二)—— 提交并生成订单

news/2024/5/9 3:55:39/文章来源:https://blog.csdn.net/weixin_30597269/article/details/95121450

本系列所有文章

如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念

如何一步一步用DDD设计一个电商网站(二)—— 项目架构

如何一步一步用DDD设计一个电商网站(三)—— 初涉核心域

如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户

如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发

如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文

如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车

如何一步一步用DDD设计一个电商网站(十一)—— 最后的准备

如何一步一步用DDD设计一个电商网站(十二)—— 提交并生成订单

如何一步一步用DDD设计一个电商网站(十三)—— 领域事件扩展

 

 

阅读目录

  • 前言
  • 解决数据一致性的方案
  • 回到DDD
  • 设计
  • 实现
  • 结语

 

一、前言

  之前的十一篇把用户购买商品并提交订单整个流程上的中间环节都过了一遍。现在来到了这最后一个环节,提交订单。单从业务上看,这个动作的背后包含了多个业务操作,根据用户填写的订单信息生成订单、扣除使用的余额和积分、使用选择的礼券等等。其中涉及到多个上下文的操作,包括新引入的订单上下文,那么如何同时与多个上下文进行数据的写入操作是本篇主要想讨论的问题。

 

二、解决数据一致性的方案

  分布式系统中的多个子系统之间的同时写入问题,也就是所谓的数据一致性问题。讲解决数据一致性方案的文章比较多,我就不赘述了,其中的根本是CAP理论,大家可自行百度/Google下。总结一下一般在分布式场景中无非就是两种方式来解决:2阶段提交的强一致性(选择CP)或者最终一致性(选择AP)。2阶段提交大家都懂,是性能杀手,阻塞式的操作会导致整个系统的瓶颈提早到来。最终一致性是非阻塞式的异步机制,通过消息体在多个系统内流转,并各自根据消息体来处理不同的业务,并且最终一致性有很多种形式来实现,这里暂不展开讨论。

 

三、回到DDD

  在DDD中实现最终一致性需要引入一个之前一直没提到的概念:领域事件。

  问1:什么是领域事件?

  答:领域事件是领域的一部分,表示领域中所发生的事情。

  问2:它存在的作用是?

  答:①作为实现最终一致性的载体

    ②解耦

    ③通过事件让不同的上下文分散处理下游业务,减少对数据的反向获取。处理单元更小化。  

    ④对开闭原则(OCP:Open-Closed Principle)最好体现。

  问3:那么我们如何运用到DDD中?

  答:①哪怕是同一个上下文中的不同聚合也需要通过领域事件来进行同步。

    ②把领域事件设计成聚合,但是其中的大部分代表事件发生与过去的部分属性应该为只读。设计为聚合拥有了唯一标识这样便于跟踪事件、持久化和跨限界上下文交互。

    ③使用发布 —— 订阅的方式来处理事件,降低耦合。

    ④有时,有必要使用领域服务来注册事件订阅方。这样的动机可能和让应用服务来注册订阅方一样,但是此时我们可能有特定于领域的原因。

    ⑤领域事件的一个经验法则是这样的:领域事件中所包含的信息应该满足80%的消费方,虽然对于很多消费方来说,这些信息是多余的。

 

四、设计

  根据上面的描述,设计了以下的几个对象进行实现领域事件的发布和订阅,如下图1:

                  【图1】

  DomainEventBus是一个单例。事件(继承自DomainEvent)的发布全部经由它来处理,分发失败的时候会抛出一个DistributeExceptionEvent的事件,由调用方决定后续的处理方式。另外事件订阅者(继承自DomainEventSubscriber)也通过DomainEventBus来注册订阅。类型依赖图如下图2:

                      【图2】

 

五、实现

  为了能够比较直观的表达当前这个提交订单业务操作的处理流程,我粗略画了个时序图,如下图3。

                          【图3】

  这里的事件发布是订单上下文内的一个组件,是一个进程内操作。另外事件具体发布的目的地由不同的订阅者控制,暂时就列出了2个。

  好了根据上面的时序图描述,下面贴出其中的核心代码:

  1.事件订阅

            var types = Assembly.Load("Mall.Domain.Order.DomainEventSubscribers").GetTypes().Where(ent => !ent.IsGenericType && ent.GetInterface(typeof(IDomainEventSubscriber).FullName) != null).ToList();foreach (var type in types){var subscriberInstance = Activator.CreateInstance(AppDomain.CurrentDomain, type.Assembly.FullName, type.FullName).Unwrap();var subscriber = (IDomainEventSubscriber)subscriberInstance;DomainEventBus.Instance().Subscribe(subscriber);}

  2.和2个对订单创建事件的订阅者

    public class OrderCreatedSubscriberPaymentContext : DomainEventSubscriber<OrderCreated>{public override void HandleEvent(OrderCreated domainEvent){//TODO anythingthrow new NotImplementedException();}}
    public class OrderCreatedSubscriberSellingPriceContext : DomainEventSubscriber<OrderCreated>{public override void HandleEvent(OrderCreated domainEvent){//TODO anythingthrow new System.NotImplementedException();}}

  3.事件发布

        public Result Create(OrderRequest orderRequest){if (!string.IsNullOrWhiteSpace(orderRequest.CouponId)){var couponResult = DomainRegistry.SellingPriceService().IsCouponCanUse(orderRequest.CouponId, orderRequest.OrderTime);if (!couponResult.IsSuccess)return Result.Fail(couponResult.Msg);}var orderId = DomainRegistry.OrderRepository().NextIdentity();var order = Domain.Order.Aggregate.Order.Create(orderId, orderRequest.UserId, orderRequest.Receiver,orderRequest.CountryId, orderRequest.CountryName, orderRequest.ProvinceId, orderRequest.ProvinceName,orderRequest.CityId, orderRequest.CityName, orderRequest.DistrictId, orderRequest.DistrictName,orderRequest.Address, orderRequest.Mobile, orderRequest.Phone, orderRequest.Email,orderRequest.PaymentMethodId, orderRequest.PaymentMethodName, orderRequest.ExpressId,orderRequest.ExpressName, orderRequest.Freight, orderRequest.CouponId, orderRequest.CouponName, orderRequest.CouponValue, orderRequest.OrderTime);foreach (var orderItemRequest in orderRequest.OrderItems){order.AddOrderItem(orderItemRequest.ProductId, orderItemRequest.Quantity, orderItemRequest.UnitPrice, orderItemRequest.JoinedMultiProductsPromotionId, orderItemRequest.ProductName);}DomainRegistry.OrderRepository().Save(order);DomainEventBus.Instance().Publish(new OrderCreated(order.ID, order.UserId, order.Receiver));return Result.Success();}

  注意其中标红的部分,暂时没有考虑出现异常的情况。另外这里的OrderCreated事件只是象征性的写一下,实际的事件需要哪些属性,只要贯彻好二八原则,设计一个满足80%场景下的直接可用,剩下的20%可以增加一些查询来满足实际业务需要。 

 

六、结语

  如果说领域对象、应用层、仓储层等这些概念还和传统的三层架构傻傻分不清楚的话。那么领域事件应该是整个DDD中最容易理解的一部分概念,因为这一部分是独立于传统的三层架构之外的完全不同的部分,也是整个DDD设计中低耦合的关键。本篇先进行了一个对领域事件最简单的实现,主要阐述了领域事件在整个项目设计过程中的作用和运用的方式。这是一个基础,在这个基础之上已经有很多成熟的解决方案可以让我们的系统做的更好。下篇会主要讲关于异常的处理(上文中标红的那部分),数据一致性的保证等更好的提高系统可用性的部分。谢谢各位看官。

 

 

本文完整的源码地址:https://github.com/ZacharyFan/DDDDemo/tree/Demo12。

 

作者:Zachary_Fan
出处:http://www.cnblogs.com/Zachary-Fan/p/DDD_12.html

 

 

▶关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描右侧的二维码~。

定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。

 

如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。

如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

转载于:https://www.cnblogs.com/Zachary-Fan/p/DDD_12.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_763760.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何根据关键字搜索网站中的内容_如何利用SEO关键字提升排名

越来越感觉&#xff0c;关键字太重要了&#xff1a;关键字就是你和目标受众之间的纽带。你的受众通过关键字发现你&#xff0c;而你&#xff0c;则通过关键字找到受众。关键字是SEO的重中之重。这篇文章介绍了为什么要重视关键字、如何找到关键字和如何使用关键字。文章重点&am…

ecs 云服务器 管理控制台_记录一下自己的建站过程(七)阿里云ECS云服务器的使用...

前言架设http软件服务之后&#xff0c;是时候考虑一下硬件架构了。自己搭一台物理机并且搞定外网环境不太好搞&#xff0c;那就试试现在小服务小集群很常用的云计算服务吧&#xff01;选用部分打开阿里云官方网站 阿里云&#xff0c;找到弹性计算&#xff0c;就有云服务器ECS&a…

Fiddler是最强大最好用的Web调试工具之一--网站抓包分析

Fiddler 教程 Fiddler是最强大最好用的Web调试工具之一&#xff0c;它能记录所有客户端和服务器的http和https请求&#xff0c;允许你监视&#xff0c;设置断点&#xff0c;甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说&#xff0c;都有很大的帮助。 阅读目录 Fid…

大型网站架构系列一:负载均衡详解(1)

面对大量用户访问、高并发请求&#xff0c;海量数据&#xff0c;可以使用高性能的服务器、大型数据库&#xff0c;存储设备&#xff0c;高性能Web服务器&#xff0c;采用高效率的编程语言比如(Go,Scala)等&#xff0c;当单机容量达到极限时&#xff0c;我们需要考虑业务拆分和分…

如何获取qlabel里面的图片_一键删除图片背景,这个网站你值得收藏!

在《这样做读书笔记&#xff0c;书看完之后想忘都忘不掉》一文中&#xff0c;我们介绍过如何制作PPT版的读书笔记&#xff0c;在实际操作的过程中&#xff0c;你可能还会遇到两个问题。第一&#xff0c;在哪里可以下载到比较高质量的书籍图片&#xff1f;第二&#xff0c;怎样删…

锚链接点击添加class_网站锚文本必做这对优化效果影响很大

锚文本,优化效果不论是针对搜索引擎还是用户&#xff0c;锚文本的建立都是非常重要的&#xff0c;不只能够促进蜘蛛多网站的抓取&#xff0c;同时也可以提升网站的用户体验&#xff0c;建立质量度比拟高的锚文本&#xff0c;便能够促进网站排名的提升。一&#xff0c;引导方向&…

iis express 无法访问此网站

选择项目&#xff0c;右击选择【属性】&#xff0c;不要勾选【覆盖应用程序根URL(U)】,或让【覆盖应用程序根URL(U)】下面的输入框和上面的输入框的地址一样! 转载于:https://www.cnblogs.com/come-on-come-on/p/7803761.html

为什么linux访问不到文件夹,laravel部署到linux,将public文件夹指定为网站根目录,但是无法访问其子文件夹...

本机使用的是window环境,一切正常,但是部署到linux系统上(配的是nginx),在访问的时候,控制器和方法都能正常执行,页面也可以输出,但是输出的页面却缺少css文件,一查是500错误,已经将请求重定向到public文件夹下,我的目录结构是:public/web/css/css.css域名是:aaa.com直接访问aa…

发布内部的普通非加密Web网站

发布内部的普通非加密Web网站 &#xff08;2009-1-9&#xff09;实验&#xff1a;发布内部的普通非加密Web网站&#xff08;通过IP地址访问&#xff09;&#xff08;HttpISA ServerHttp&#xff09; 注意&#xff1a;被发布的Web网站所在的计算机必须被配置为SecureNAT客户端。…

【Python】探测网站是否可以访问

首先贴上简陋的python脚本 #coding:utf-8import urllib,linecachefor line in linecache.updatecache(url.txt):try:code urllib.urlopen(line.strip(\n)).getcode() print codeexcept Exception,e:print e if code 200:with open(url_new.txt,a) as fw:fw.write(li…

selenium验证码登录_如何用 Python 登录主流网站,爬取一些需要的数据

最近收集了一些网站的登陆方式和爬虫程序&#xff0c;有的通过 selenium 登录&#xff0c;有的则通过抓包直接模拟登录。作者希望该项目能帮助初学者学习各大网站的模拟登陆方式&#xff0c;并爬取一些需要的数据。作者表示模拟登陆基本采用直接登录或者使用 seleniumwebdriver…

PHP网站目录管理脚本,兼容PHP5的PHP目录管理函数库

兼容PHP5的PHP目录管理函数库更新时间&#xff1a;2008年07月10日 23:43:03 作者&#xff1a;php下进行目录的一些操作&#xff0c;经常用到的方法主要能兼容&#xff1a; PHP 5一、chdir -- 改变目录语法&#xff1a;bool chdir ( string directory )返回值&#xff1a;整数…

服务器开机修复,win10开机怎么进修复模式_网站服务器运行维护

win10开机闪屏进不去怎么解决_网站服务器运行维护win10开机闪屏进不去的解决方法&#xff1a;首先重启2次进入安全模式&#xff1b;然后点击疑难解答-高级选项&#xff1b;最后在高级选项中选择恢复到之前的正确系统即可。win10开机怎么进修复模式1、首先&#xff0c;大家先打开…

怎末吧做好的网站放到服务器里,将做好的网站放到云服务器上

将做好的网站放到云服务器上 内容精选换一换通过华为云备案&#xff0c;需要先购买华为云中国大陆节点服务器&#xff0c;用于网站备案使用&#xff0c;后称为“备案服务器”。目前可用于华为云备案的服务器&#xff0c;请参见备案服务器。如果您的华为云帐号A中没有可备案的服…

常见的网站服务器架构有哪些?

以下的架构都是在假设已经优化过linux内核的情况下进行&#xff1a;初级篇&#xff1a;&#xff08;单机模式&#xff09;假设配置&#xff1a;&#xff08;Dual core 2.0GHz,4GB ram,SSD&#xff09;基础框架&#xff1a; apache(PHP) Mysql / IIS MSSQL&#xff08;最基础…

php5.2架设网站,FreeBSD 6.2快速架设网站服务器教程(Apache2.2.X+MySQL5.X.X+ PHP5.2.X+ ZendOptimizer-3.2.X)...

世界网络教研室整理1、 安装设置prozilla(port下载加速)当然是首先安装下载加速啦&#xff0c;不然下面的安装会好慢的安装使用如下指令&#xff1a;#cd /usr/ports/ftp/prozilla#make install clean中间会出现&#xff1a;这是例子和HTML格式的手册页&#xff0c;不会用以后想…

JSsearch实现在购物网站输入后推荐联想的效果

在篇文章里&#xff0c;我们主要讲解一下JSsearch如何完成推荐的功能 首先&#xff0c;登陆码云下载JSsearch&#xff1a; https://gitee.com/skyogo/JSsearch 我们下载JSsearch1.0 Community版本 下载好了之后我们再下载一个类似淘宝的购物页面&#xff08;页面由达内童程制作…

自学电脑编程_有哪些高质量的自学网站

1、羽兔网羽兔网是一个以设计类为主的自学网站&#xff0c;有大量免费课程给大家学习&#xff0c;不管是平面设计&#xff0c;ui设计&#xff0c;电商设计各类热门设计软件课程都有。羽兔网-视频教程线上学​www.yutu.cn2、溜溜自学网一个热门专业为主的自学网&#xff0c;想学…

dw模板文件的扩展名_网站单页面模板制作和dede默认文件夹名称解释

之前我们已经完成了网站首页的制作&#xff0c;操作过就有经验了&#xff0c;其他的工作就简单很多。这里来说一下单页面的模板制作。一 、和首页一样&#xff0c;首先用仿站小工具输入要下载的单页面域名&#xff0c;下载网站内容&#xff0c;上次下载的首页内容可以删掉了二 …

vs新建网站选项只有wcf服务器,WCF教程一:新建并部署

一、概述Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口&#xff0c;可以翻译为Windows通讯接口&#xff0c;它是.NET框架的一部分。由 .NET Framework 3.0 开始引入。WCF的最终目标是通过进程或不同的系统、通过本地网络或是通过Interne…