如何一步一步用DDD設計一個電商網站(二)—— 項目架構

来源:http://www.cnblogs.com/Zachary-Fan/archive/2016/10/31/6012454.html
-Advertisement-
Play Games

閱讀目錄 前言 六邊形架構 終於開始建項目了 DDD中的3個臭皮匠 CQRS(Command Query Responsibility Segregation) 結語 閱讀目錄 前言 六邊形架構 終於開始建項目了 DDD中的3個臭皮匠 CQRS(Command Query Responsibilit ...


閱讀目錄

一、前言

    上一篇我們講了DDD的核心概念(附上鏈接),並且設計了我們的上下文映射圖,那麼接下來就準備開始立項了,本篇文章的部分知識點可能對一部分人來說比較基礎,可以選擇性的閱讀。

    在這之前我們平常用的最多的應該就是3層架構了,這裡也不展開描述了,大家都是在3層的陪伴下一路走來的~

    DDD所使用的傳統分層架構是鬆散分層,也就是上層可以訪問任意層級的下層,而不是僅限於當前層的下一層,這是有別於3層架構的。如下麵2張圖的區別圖:

      

                        【圖1】

  

                        【圖2】

Application:這層的職責是對接收到的數據做一些非業務性驗證,事務的控制,最重要的是協調多個聚合之間的操作。這裡應該可以清晰的表達出整個操作所做的事情,並且與通用語言是一致的。

Domain:這一層是DDD設計的核心,這裡不但需要精確合理的表達出通用語言的每一個細節,另外如何把對象合理的定義為聚合、實體、值對象也是重中之重。這裡不但關係著整個項目的複雜度,也是戰術建模的體現,任何的一行代碼都是對業務的準確定義,應該是恰到好處。一個清晰簡潔的戰術建模才可以應對後續的快速變化。

Infrastructure:這裡是輔助性的一層,也是整個項目的基礎。好比這裡存放著一磚一瓦,最終建造什麼模樣的高樓在於用它的地方。主要包括,倉儲的實現(我們存放數據的地方)、一些通用的支撐性類庫。

 

二、六邊形架構

    在[Vaughn Vernon]《實現領域驅動設計》一書中多次提到對DDD主張六邊形架構的概念,六邊形架構對於保證限界上下文內的領域概念的清晰性有著重要的作用,那麼什麼是六邊形架構,如下圖3(摘自[Vaughn Vernon]《實現領域驅動設計》一書)。

  

                      【圖3】

    在當今越來越提倡開放合作的大環境下,引用的多樣化的Service,和在自身系統達到一定規模之後的分散式治理,越來越需要通過協作進行工作,那麼如何提升協作的效率變得越來越重要。提高各個應用程式的自治性,是一種有效提升協作能力的手段。從上圖中看出為了保證領域模型所在的應用程式的乾凈簡潔和自治性,各種適配器作為"防腐層(在上篇中有提到)"在整個程式的最外層保護著當前的“界限上下文(在上篇中有提到)”不受外部入侵。

    所以在我們的整個設計中需要註意對涉及到外部系統交互的地方的抽象,通過面向介面、依賴註入等方式做到外部的變化對自身系統的影響最小化。

 

三、終於開始建項目了

    按照之前的這些描述,我們終於初步建立了我們的解決方案。如下圖4:

  

                【圖4】

這裡把每個項目的職責大致說一下。

Mall:負責我們的電商網站的界面處理和用戶的數據錄入

Mall.Application:按模塊分別定義不同的ApplicationService來講述每一個操作下的“故事”。

Mall.Application.DomainEventSubscribers:所有的領域事件訂閱者。

Mall.Domain:這裡存放著戰術建模的結晶,Entity、Aggregate、ValueObject。(下麵會具體講述下)

Mall.Domain.Events:所有的領域事件,這層也可以合併到Domain中,給它新建一個文件夾。

Mall.Domain.IRepositories:所有的倉儲(資源庫)介面。類似於三層中的IDAL。

Mall.DomainService:領域服務,存放著那些不適合放在聚合/值對象上的無狀態的操作方法,用於實現特定某個領域的任務。

Mall.Infrastructure:存放著一些通用類庫

Mall.Infrastructure.Repositories:所有倉儲(資源庫)的實現。

Mall.Infrastructure.Translators:翻譯層,也就是與外部系統溝通的橋梁,主要的職責就是做好“反腐層”的重任。

 

四、DDD中的3個臭皮匠

    這裡的3個臭皮匠其實就是:Entity、ValueObject、Aggregate。我們要提煉出業務中的精華,合理的抽象為這3個概念,並且這種抽象是需隨著領域里的概念變化而變化的。這3者的結合運用會讓我們的項目活起來,這是DDD的核心。這裡再把這3個概念重新梳理一下。

    Entity(實體): 每個實體是唯一的,並且可以相當長的一段時間內持續地變化。我們可以對實體做多次修改,故一個實體對象可能和它先前的狀態大不相同。但是,由於它們擁有相同的身份標識,他們依然是同一個實體。

    ValueObject(值對象):值對象用於度量和描述事物,當你只關心某個對象的屬性時,該對象便可作為一個值對象。實體與值對象的區別在於唯一的身份標識和可變性。

    Aggregate(聚合):聚合類是實體的升級,是由一組與生俱來就密切相關實體和值對象組合而成的,這整個組合的最上層實體就是聚合。

 

五、CQRS(Command Query Responsibility Segregation)

    說到DDD必然要提一下CQRS,我認為CQRS和DDD的關係就像咖啡和牛奶,給大型系統的構建提供了一劑良藥,它生於讀寫分離,具有高吞吐量、高伸縮性等特點,值得我們為之付出一些代價。但是CQRS的使用會使整個數據持久化和查詢的鏈路拉長,並且工作量也會比簡單的讀寫一體化大的多,所以需要對項目做出合理的考量來決定是否使用。

    當我們需要把某個複雜的聚合修改之後寫入到資料庫的時候,要保證N張表的數據被同時修改成功,整個事務的周期必然會加長。而且當我們需要顯示來自不同聚合類型與實例的數據時,我們的SQL必然包含N多的join。領域越複雜這種情況越發常見。

    CQRS需要和事件源結合使用,對數據的修改操作只是往事件源里增加一條修改後的結果記錄(類似於我們的源碼控制軟體的log),並不會直接把修改後的對象持久化到資料庫。這樣能夠大大提高數據修改的速度,並且對於查詢操作的實現方式就比較多樣化了。大致列舉了以下4種方式:

    1.還是使用單個資料庫,每次領域對象的獲取都需要根據事件源中的事件集合做重建,得到當前的最新的數據返回。這隻是編碼設計上的讀寫分離

    2.拆分為讀庫和寫庫,實現方式同1

    3.拆分為讀庫和寫庫,並且針對讀庫做專門的查詢數據冗餘,非同步的通過事件源來修改查詢數據,可以結合merge commit。

    4.在3的基礎上做讀庫的負載均衡

    這4種方式複雜度各不相同,可以結合實際項目的複雜度擇優選擇,其中最關鍵的一條便是是否存在大量的列表類數據展示,如果是那麼1和2便就不適合了。在以上的方式之外可以結合其他的數據存儲一起使用,如緩存,NoSql,然而這隻需要訂閱所有的命令事件即可實現。

 

六、結語

    本篇主要介紹了項目的分層架構、每層的職責和裡面存放什麼樣子的類。限於非我們這個系列的核心主題,所以都沒有發散出去做更加具體形象的描述,希望大家可以邊結合[Vaughn Vernon]《實現領域驅動設計》一書的閱讀跟著我做實際的編碼來加深對DDD的理解。跳出根深蒂固的三層思想是痛苦的,但是我認為只要堅持下去,DDD會讓你看見一片世外桃源,到那時會覺得我們的付出都是值得的。並且DDD思想的運用可大可小,小到類的設計,大到複雜項目之間的構架,都會給你提供幫助。

 

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


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

-Advertisement-
Play Games
更多相關文章
  • mybatis generator 修改xml文件後啟動Tomcat伺服器時出現的Result Maps collection already contains value for BaseResultMap異常, ...
  • 1. java程式 2 編譯 javac TestHello.java 3. 生成c++頭文件 javah TestHello 4. 創建 DLL動態鏈接庫工程 TestHello visual studio 2010: File->new->project->win32 project-> dll ...
  • #!/usr/bin/env python# -*- coding: utf-8 -*-#如下是一個購物程式:#先輸入工資,顯示商品列表,購買,quit退出,最後格式化輸出所買的商品。count = 0while True: #做一個迴圈判斷,如果輸入的不是數字,基於提示,三次後退出 salary ...
  • 1.1概述 定義一個用於創建對象的介面,讓子類決定實例化哪一個類。Factory Method使一個類的實例化延遲到其子類。這就是工廠方法模式的定義。 得到一個類的子類的實例最常用的辦法就是使用new運算符和該子類的構造方法,但是在某些情況下,用戶可能不應該或無法使用這種辦法來得到一個子類的實例,其 ...
  • 像activeMQ等消息隊列中,我們經常會使用發佈訂閱模式,但是你有沒有想過,客戶端時如何及時得到訂閱的主題的信息?其實就裡就用到了觀察者模式。在軟體系統中,當一個對象的行為依賴於另一個對象的狀態時,觀察者模式就相當有用。如果不使用觀察者模式提供的通用結構,而需要我們實現類似的功能,想想我們該如何實 ...
  • 前言 今天複習一下SpringMVC+Hibernate的搭建,本來想著將Spring-Security許可權控制框架也映入其中的,但是發現內容太多了,Spring-Security的就留在下一篇吧,這篇主要搭建SpringMVC4.1.4和Hibernate4.3.8,之前也打了好多SpringMV ...
  • 轉自:https://yq.aliyun.com/articles/8611 微服務架構的理論基礎 - 康威定律 摘要可能出乎很多人意料之外的一個事實是,微服務很多核心理念其實在半個世紀前的一篇文章中就被闡述過了,而且這篇文章中的很多論點在軟體開發飛速發展的這半個世紀中竟然一再被驗證,這就是康威定律 ...
  • 在我的博客《Hibernate總結(一)》在對資料庫的增刪改查前後重覆的使用了得到Session與關閉Session等操作,因此我想到了模板設計模式。 模板設計模式概述: 定義一個操作中的演算法的骨架,而將步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義演算法的某些特定步驟。 廢話不 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...