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

news/2024/5/8 12:35:09/文章来源:https://blog.csdn.net/weixin_30641999/article/details/95121455

 

本系列所有文章

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

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

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

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

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

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

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

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

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

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

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

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

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

 

 

阅读目录

  • 前言
  • 准备
  • 实现
  • 结语

 

一、前言

  最近实在太忙,上周停更了一周。按流程一步一步走到现在,到达了整个下单流程的最后一公里——结算页的处理。从整个流程来看,这里需要用户填写的信息是最多的,那么在后端的设计中如何考虑到业务边界的划分,和相互之间的交互复杂度,又是我们需要考虑的地方。总体来说本篇讲述的内容在前几篇都有涉及,所以这次一次性处理的业务比较多,已经比较熟练的看官可以跳过本篇。

 

二、准备

  主流的电商设计中结算页包含以下5个概念:选择收货地址、选择支付方式、选择快递、使用优惠券、使用余额和积分。笔者认为,根据我们在本系列的第一篇博文中的上下文映射图,这背后涉及到了多个上下文的协作:

  1.用户上下文:包含选择收货地址

  2.支付上下文:包含选择支付方式、使用余额和积分

  3.售价上下文:使用优惠券。

  其中第“1”点我的理解是在整个大系统中,收货地址并不是仅在购买的时候会用到,而是用户可以直接管理的(一般主流电商都可以在《用户中心》菜单内操作个人的收货地址信息),在购物车中进行管理其实并不是一个必须经过的流程,大部分场景下只是在现有地址中做一个选择,所以收货地址更接近于用户域而不是购买域,在购物车的管理可以理解为一个快捷方式而已。

  第“2”点,我的理解是,把支付操作相关的概念放到一起,可以做的很灵活,可以和运营打法搭配起来。如:支付方式和使用积分的联动、像天猫那样的红包等促进用户购买欲望的招式。

  第“3”点,我的理解是,优惠券也是会影响到整个商品的售价的,所以它应该属于售价上下文,配合其它的促销方式做出更多的打法。

  剩下的快递我认为是本地购买上下文内的概念,因为它只服务于购买的流程之中。

 

三、实现

  根据服务能力来编写ApplicationService,那么这里总共是提供了3种服务能力,所以定义了3个ApplicationService来提供这些功能:

  1.IDeliveryService:其中包含选择收货地址和选择快递

  2.IPaymentService:其中包含选择支付方式、使用余额和积分

  3.ICouponService:包含选择礼券。

  好了接下来就是其中涉及到的领域模型的设计,这里需要纠正一个之前的错误,在之前的设计中把余额直接放到了User这个值对象中,并且是从用户上下文获取的,现在看看当初的设计不是很妥当。因为余额并不是用户与生俱来的东西,就好比我要认识一个人,并不一定要知道他有多少钱,但是必然需要知道姓名、年龄等。所以余额与用户之间并不是一个强依赖关系。而且分属于2个不同的领域聚合、甚至是上下文。这里涉及的所有领域模型的UML图如下图1所示:

                          【图1】

  其中的值对象都是从远程上下文获取的,所以这里在购买上下文里只是使用了其的一个副本。在购买上下文的3个ApplicationService如下:

    public interface IDeliveryService{List<ShippingAddressDTO> GetAllShippingAddresses(string userId);Result AddNewShippingAddress(string userId, DeliveryAddNewShippingAddressRequest request);Result EditShippingAddress(string userId, DeliveryEditShippingAddressRequest request);Result DeleteShippingAddress(string id);List<ExpressDTO> GetAllCanUseExpresses();}
    public interface IPaymentService{List<PaymentMethodDTO> GetAllCanUsePaymentMethods();WalletDTO GetUserWallet(string userId);}
    public interface ICouponService{List<CouponDTO> GetAllCoupons(string userId);}

  这里接口定义思路是把界面上的操作记录全部由UI程序做本地缓存/Cookie等,减少服务端的处理压力,所以接口看上去比较简单,没有那些使用礼券,修改使用的收货地址这类的接口。

  另外提一下,在当前的解决方案中的售价上下文中的处理中,增加了2个聚合来处理优惠券相关的业务。

    public class Coupon : AggregateRoot{public string Name { get; private set; }public decimal Value { get; private set; }public DateTime ExpiryDate { get; private set; }public List<string> ContainsProductIds { get; private set; }public Coupon(string name, decimal value, DateTime expiryDate, IEnumerable<string> containsProductIds){if (string.IsNullOrWhiteSpace(name))throw new ArgumentNullException("name");if (value <= 0)throw new ArgumentException("value不能小于等于0", "value");if (expiryDate == default(DateTime))throw new ArgumentException("请传入正确的expiryDate", "expiryDate");if (containsProductIds == null)throw new ArgumentNullException("containsProductIds");this.Name = name;this.Value = value;this.ExpiryDate = expiryDate;this.ContainsProductIds = containsProductIds.ToList();}}
    public class CouponNo : AggregateRoot{public string CouponId { get; private set; }public DateTime UsedTime { get; private set; }public bool IsUsed{get { return UsedTime != default(DateTime) && UsedTime < DateTime.Now; }}public string UserId { get; private set; }public CouponNo(string couponId, DateTime usedTime, string userId){if (string.IsNullOrWhiteSpace(couponId))throw new ArgumentNullException("couponId");if (string.IsNullOrWhiteSpace(userId))throw new ArgumentNullException("userId");this.CouponId = couponId;this.UsedTime = usedTime;this.UserId = userId;}public void BeUsed(){this.UsedTime = DateTime.Now;}}

  其中CouponNo中的CouponId是保持了一个对Coupon聚合ID的引用,在需要的时候从Repository中取出Coupon的信息。部分代码如下:

            var couponNos = DomainRegistry.CouponNoRepository().GetNotUsedByUserId(cart.UserId);var buyProductIds = cart.CartItems.Select(ent => ent.ProductId);List<CouponDTO> couponDtos = new List<CouponDTO>();foreach (var couponNo in couponNos){if (couponNo.IsUsed)continue;var coupon = DomainRegistry.CouponRepository().GetByIdentity(couponNo.CouponId);if (coupon.ContainsProductIds.Count == 0 || coupon.ContainsProductIds.Any(ent => buyProductIds.Any(e => e == ent))){couponDtos.Add(new CouponDTO{CanUse = couponNo.IsUsed,ExpiryDate = coupon.ExpiryDate,ID = couponNo.ID,Name = coupon.Name,Value = coupon.Value});}}

 

 

四、结语

  本篇比较简单不多述了,下面源码奉上,有兴趣的同学自行下载查看全部源码。

 

 

 

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

 

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

 

 

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

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

 

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

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

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

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

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

相关文章

新网站如何做SEO优化

&ldquo;百度快照变慢了、百度收录问题、关键词掉了&rdquo;&#xff0c;这是在卢松松留言本被经常问及的问题&#xff0c;新手站长往往会因此吃不下饭、睡不着觉&#xff0c;网站的推广是一个漫长的过程&#xff0c;&ldquo;心急吃不了热豆腐&rdquo;&#xff0c;…

《大型网站技术架构:核心原理与案例分析》-- 读书笔记 (1):大型网站发展历程...

网站架构发展 1 初始阶段 -- 只有一台服务器 2 应用服务和数据服务分离 3 使用缓存改善网站性能 4 使用应用服务器集群改善网站并发处理能力 5 数据库读写分离 6 使用反向代理和CDN加速网站响应 反向代理和CDN的基本原理都是缓存&#xff0c;区别在于CDN部署在网络提供商的机房…

如何给WordPress网站更换域名

网站更换域名是站长们经常遇到的网站处理问题&#xff0c;wordpress程序网站换域名主要包括如下几步&#xff0c;希望大家能够认真参考实践。 第一步&#xff1a;将自己的新域名DNS解析到自己的服务器或是空间ip上&#xff0c;ip绑定新域名。 第二步&#xff1a;进入你的网站数…

mouseover和mouseenter的区别

_谦龙 发布在谦龙的小天地2017年6月5日view&#xff1a;111HTML5BrettBat性能优化正则表达式前端工程师面试闭包高阶函数DOMES6在文章任何区域双击击即可给文章添加【评注】&#xff01;浮到评注点上可以查看详情。 隐藏标注前言 原文地址 项目地址 不知道大家在面试或者工作过…

百度云主机使用WordPress建站ideashare.club过程总结与那些坑

目录 为什么建站&#xff1f; 购买主机 配置主机 购买域名 ICP备案 解析域名 WordPress安装 申请SSL证书 踩过的那些坑&#xff1a; 1&#xff0c;域名解析的设置 2&#xff0c;隐私保护开关操作失败 3&#xff0c;开启了SSL证书以及wordpress的HTTPS插件&#xff…

居然有网站抄袭我的博客内容,但我很高兴!

今天唠叨点家常&#xff0c;说点高兴的事&#xff01; 也许有人会因为文章被抄袭了而烦恼&#xff0c;或者觉得自身利益受损&#xff0c;感到非常失望。 不过我前几天被网友告知文章出现在了其它地方&#xff0c;浏览量比较高&#xff0c;这点却甚是欣慰&#xff0c;毕竟开博客…

记一次更换网站SSL证书--打包在traefik里面使用docker部署

突然发现网站访问时提示&#xff1a;您的连接不是私密连接 攻击者可能会试图从 www.xxxxx.com 窃取您的信息&#xff08;例如&#xff1a;密码、通讯内容或信用卡信息&#xff09;。了解详情 NET::ERR_CERT_DATE_INVALID&#xff0c;这就很尴尬了&#xff0c;第一次遇到这种情况…

记一次使用nginx部署静态网站

nginx部署静态网站:1.查找nginx安装目录&#xff1a;2.测试配置文件是否能正确加载由于拿到的服务器已经安装好nginx了&#xff0c;访问服务器ip可以看到nginx的欢迎页。 那么直接配置映射静态网站就好了。 1.查找nginx安装目录&#xff1a; 使用命令&#xff1a;whereis ng…

全世界最著名的 icon 网站都在这了

<link rel"stylesheet" href"https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f76675cdea.css"><div class"htmledit_views" id"content_views">作为一个多年的独立开发者&#xff0c;收藏了非常多免…

Tomcat 自定义默认网站目录

上面访问的网址为http://192.168.0.108:8080/memtest/meminfo.jsp 需求&#xff1a; 现在我想访问格式为http://192.168.0.108:8080/meminfo.jsp 方法一 将meminfo.jsp或其他程序放在tomcat/webapps/ROOT目录下即可。因为默认网站根目录为tomcat/webapps/ROOT [rootmysql webap…

资源 | 11个免费矢量免抠素材网站

PNGAll&#xff08;推荐指数&#xff1a;❤❤❤❤&#xff09; PNGAll.com是一个信息网络博客&#xff0c;免费为用户提供最优质的PNG透明图像 国外网站&#xff0c;比较简洁&#xff0c;仅支持英文搜索&#xff0c;建议使用浏览器翻译插件 网站&#xff1a;www.pngall.com …

免抠图PNG素材网站

今天再给大家补充两个非常棒的免抠图PNG素材网站&#xff08;一个国内、一个国外&#xff09; 一、觅元素 http://www.51yuansu.com 国内网站&#xff0c;提供各类PSD、PNG、AI等多种格式的素材和背景下载&#xff0c;比如我们搜索逐灯笼&#xff0c;可以看到素材的质量非常高…

CPU,内存占用很低,mysql没有死锁,但是网站出现卡顿现象

目前维护的网站&#xff0c;出现了卡顿现象&#xff0c;查看原因&#xff1a; 第一步、使用top命令查看内存和cpu使用情况&#xff1a; 第二步、查看mysql的占用情况&#xff1a; 第三步&#xff0c;查看IO占用情况&#xff1a; 使用命令iostat -x 1 10 %util 代表磁盘繁忙程…

网站安全TOP10问题及其解决方案

网站安全 最常见的网站安全问题TOP10 1、Injection. 将不受信任的数据作为命令或查询的一部分发送到解析器时&#xff0c;会产生诸如SQL注入、NoSQL注入、OS 注入和LDAP注入的注入缺陷。攻击者的恶意数据可以诱使解析器在没有适当授权的情况下执行非预 期命令或访问数据。 …

网站浏览器可以打开,在微信中打不开,排查问题的过程

今天收到遇到一个诡异的问题&#xff1a;网站浏览器可以打开&#xff0c;在微信中打不开&#xff0c;耗费了很长时间才将问题排查出来&#xff0c;现在将排查的步骤记录下来&#xff0c;仅供参考&#xff1a; 在手机微信里输入访问地址&#xff1a;显示无法 打开网页。如图所示…

使用docker方式搭建免费开源的境外商城网站

境外商城网站&#xff0c;可以销售国内的商品&#xff0c;将国内的商品卖到国际上 prestashop 是一个比较好用的开源免费的境外商城网站 官网&#xff1a;https://www.prestashop.com/en 搭建的步骤&#xff1a; 在云上开一台机器&#xff0c;2核4G以上的就可以 安装网络&a…

使用docker-compose搭建个人博客网站solo

solo是一款开源的个人博客网站 官网的地址&#xff1a; https://b3log.org/solo/ 搭建步骤 开通一台云上的机器 准备一个域名指向这台机器的外网IP 准备docker-compose和docker环境 没有docker和docker-compose的环境的&#xff0c;可以根据自己的操作系统&#xff0c;准备…

基于SpringBoot从零构建博客网站 - 设计可扩展上传模块和开发修改头像密码功能...

上传模块在web开发中是很常见的功能也是很重要的功能&#xff0c;在web应用中需要上传的可以是图片、pdf、压缩包等其它类型的文件&#xff0c;同时对于图片可能需要回显&#xff0c;对于其它文件要能够支持下载等。在守望博客系统中对于上传模块进行统一管理&#xff0c;同时对…

django+uwsgi+nginx部署网站

djangouwsginginx部署网站 静态&#xff1a;nginx直接处理 动态&#xff1a;wsgi或者uwsgi给python处理 uwsgi web协议&#xff0c;发布python网站。 uwsgi是服务器和服务端应⽤程序的通信协议&#xff0c;规定了怎么把请求转发给应⽤程序和返回 uWSGI实现WSGI协议&#xff0…

Certbot给网站域名申请免费SSL证书 及Nginx配置

Certbot 官网&#xff1a; https://certbot.eff.org/ 前提是自己已经安装好nginx&#xff0c;并配置好自己的域名。 1.安装snap 官网要求用snap工具安装&#xff0c;那就先安装相关依赖包&#xff0c;和snap软件。 yum -y install epel-release #安装依赖 yum -y…