如何一步一步用DDD設計一個電商網站(六)—— 給購物車加點料,集成售價上下文

来源:http://www.cnblogs.com/Zachary-Fan/archive/2016/11/30/DDD_6.html
-Advertisement-
Play Games

閱讀目錄 前言 如何在一個項目中實現多個上下文的業務 售價上下文與購買上下文的集成 結語 一、前言 前幾篇已經實現了一個最簡單的購買過程,這次開始往這個過程中增加一些東西。比如促銷、會員價等,在我們的第一篇文章(如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念)中規劃的上下文映射圖可以 ...


閱讀目錄

 

一、前言

  前幾篇已經實現了一個最簡單的購買過程,這次開始往這個過程中增加一些東西。比如促銷、會員價等,在我們的第一篇文章(如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念)中規劃的上下文映射圖可以看到,這些都屬於一個獨立的上下文(售價上下文)。

 

二、如何在一個項目中實現多個上下文的業務

  一般情況下,為了更好的分而治之,把不同的上下文作為單獨的service,然後通過rpc框架(如WCF)來對其訪問是個比較常見的做法。但是在一些小型團隊中,雖然劃分出了不同上下文,但是我們的開發團隊還是同一個。在這種情況下,我個人一般的做法是直接在同一個解決方案中建立不同的項目去做,但是這裡需要在解決方案中明確的劃分好不同上下文之間的邊界,通過代碼審核等手段管理好這個邊界不被破壞。

  

                      【圖1】

  增加的幾個項目如圖1所示。

  

三、售價上下文與購買上下文的集成

  根據我們第一篇如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念所定義的上下文映射圖和9種集成模式可以看出,這2個上下文在同一個子域中,並且在我們實際業務場景中,這2者又是相輔相成,所以售價上下文和購買上下文是一種合作關係。確立這個關係之後,那麼這個促銷的計算邏輯到底是放到哪個上下文種做更合適呢?我們先整理一下幾種可能的方式:

  1.購買上下文把購物車中的商品信息丟給售價上下文 --> 售價上下文進行計算 --> 把結果再返回給購買上下文。

  2.購買上下文從銷價上下文獲取相關會員價和促銷信息 --> 再本地的購物車對象基礎上進行運算,並直接可運用結果。

  3.再抽出一個專門的計算服務(隸屬於售價上下文),去做這個計算的動作。購買上下文把購物車中的商品信息丟給計算服務 --> 計算上下文從銷價上下文獲取到相關會員價和促銷信息 --> 計算 --> 返回結果給購買上下文

  我相信1和2是比較主流的2個方式。但是方式2是把售價上下文僅作為一種數據的提供方,這就把合作關係變成了一個上下游的關係,並且這種方式使得促銷規則和購物車強耦合到了一起,不利於促銷規則的變化。在這裡售價上下文只起了一個簡單的數據維護作用,無法完全控制“售價”的定義,沒有很好的做到職責分離。方式1和3對購買上下文來說其實是沒有區別的,只是方式3讓整個數據交互的鏈路多了一層,會產生額外的開銷,好處是服務的粒度更細了,需要結合實際情況權衡一下得失。這裡我選擇1方式來實現,因為我們在項目初期,還是儘可能的減少非業務目的的拆分導致的額外成本。

  好了,確定了集成方式之後,先把2個上下文之間用於數據交互的DTO模型定一下,如下圖2(售價上下文的DTO模型),圖3(購買上下文中與前者對應的值對象)。

 

                     【圖2】

                  【圖3】

  另外在圖3中可以發現增加了一個ISellingPriceService,抽象了與售價上下文的交互。那麼我們在Mall.Infrastructure.Translators項目中增加對這個上下文的防腐層處理,老3樣SellingPriceAdapter(發起上下文數據請求的適配器)、SellingPriceService(實現ISellingPriceService)、SellingPriceTranslator(把遠程數據對象轉換成本地的值對象),代碼很簡單大家可以在源碼中查看。需要註意的是,這裡的Mall.Infrastructure.Translators項目僅增加了對Mall.Application.SellingPrice項目的引用,類似於把它當作一個遠程資源來對待(按上面所說,如果實際由不同的團隊負責可以物理上的分離到2個解決方案中)。

  最後創建一個CartService,裡面的GetCart()方法——獲取購物車信息,來作為調用發起方。這其中的實現使用了最簡單的方式,本地不做任何的數據冗餘,代碼如下:

    public class CartService
    {
        private readonly static ConfirmUserCartExistedDomainService _confirmUserCartExistedDomainService = new ConfirmUserCartExistedDomainService();

        public CartDTO GetCart(string userId)
        {
            var cart = _confirmUserCartExistedDomainService.GetUserCart(userId);

            if (cart.IsEmpty())
            {
                return null;
            }

            var sellingPriceCart = DomainRegistry.SellingPriceService().Calculate(cart);
            return ConvertToCart(cart, sellingPriceCart);
        }

        private CartDTO ConvertToCart(Cart cart, SellingPriceCart sellingPriceCart)
        {
            return new CartDTO
            {
                CartItemGroups = sellingPriceCart.CalculatedFullGroups.Select(ent => new CartItemGroupDTO
                {
                    CartItems = ent.CalculatedCartItems.Select(e => ConvertToCartItem(e, cart.GetCartItem(e.ProductId))).ToArray(),
                    ReducePrice = ent.ReducePrice
                }).ToArray(),
                CartItems = sellingPriceCart.CalculatedCartItems.Select(ent => ConvertToCartItem(ent, cart.GetCartItem(ent.ProductId))).ToArray()
            };
        }

        private CartItemDTO ConvertToCartItem(SellingPriceCartItem sellingPriceCartItem, CartItem cartItem)
        {
            var product = DomainRegistry.ProductService().GetProduct(cartItem.ProductId);
            return new CartItemDTO
            {
                ProductId = cartItem.ProductId,
                ProductName = product == null ? "商品已失效" : product.SaleName,
                ReducePrice = sellingPriceCartItem.ReducePrice,
                SalePrice = cartItem.Price
            };
        }
    }    

 

 四、結語

  這次有個全局改動這裡提一下,我在本次編碼中把之前所有的Guid標識全部改為了string類型,弱化了對唯一標識的數據類型約束,提高可擴展性(如自增欄位、其它自定義的唯一標識等),另外還把購物項中的Price改為了UnitPrice,讓語義更加清晰。本篇內容比較粗,歡迎大家探討。

 

 

本文的源碼地址:https://github.com/ZacharyFan/DDDDemo/tree/Demo6

 

 

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Spring是SSH中的管理員,負責管理其它框架,協調各個部分的工作。今天一起學習一下Spring的事務管理。Spring的事務管理分為聲明式跟編程式。聲明式就是在Spring的配置文件中進行相關配置;編程式就是用註解的方式寫到代碼里。下麵先說聲明式: Spring配置文件中關於事務配置總是由三個組 ...
  • 前些陣子忙完了公司前端靜態頁面的事情了之後,簡單學習了下php的基礎知識,今天想了想回顧一下php連接資料庫的方式,寫一下隨筆存一下看看 php連接資料庫埠和新建資料庫 連接成功後,創建簡單的數據表 在連接資料庫的時候,要保證資料庫的伺服器埠是打開的,不然無法連接到,書寫代碼之前,可以使用nav ...
  • 1.DriverManager用來建立和資料庫的鏈接以及管理JDBC驅動程式 driverManager的常用方法 2.Connection代表Java程式和資料庫的連接 Connection的常用方法 3.Statement用來執行靜態的SQL語句。例如:對於insert,update和delet ...
  • 本視頻為activiti工作流的web流程設計器整合視頻教程 整合Acitiviti線上流程設計器(Activiti-Modeler 5.21.0 官方流程設計器) 本視頻共講了兩種整合方式 1. 流程設計器和其它工作流項目分開部署的方式 2. 流程設計器和SSM框架項目整合在一起的方式 視頻大小 ...
  • 多個中斷源在它們的搶占式優先順序相同的情況下,子優先順序不論是否相同,如果某個中斷已經在服務當中,則其它中斷源都不能打斷它;只有搶占式優先順序高的中斷才可以打斷其它搶占式優先順序低的中斷。 就是說, 組優先順序不同的時候高優先順序可以搶占低優先順序進程。 組優先順序相同的時候,子優先順序不能搶占。 ...
  • A 調用攝像頭拍照,自定義裁剪編輯頭像 B 集成代碼生成器 [正反雙向](單表、主表、明細表、樹形表,開發利器)+快速構建表單; 技術:313596790freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表sql腳本,處理類,service等完整模塊C 集成阿裡巴巴資料庫連 ...
  • 分散式學習系列【dubbo實踐】 dubbo架構 組成部分:provider,consumer,registry,monitor; provider,consumer註冊,訂閱類似於消息隊列的註冊訂閱 一、環境安裝 1、dubbo admin 管理控制台安裝(Windows環境) #下載dubbo- ...
  • HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服務端組件、客戶端組件和 Agent 組件,廣泛適用於各種不同應用場景的 TCP/UDP/HTTP 通信系統,提供 C/C++、C#、Delphi、E(易語言)、Java、Python 等編程語言介面。HP-Socket ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...