Golang領(lǐng)域模型-六邊形架構(gòu)

前言:六邊形架構(gòu)又稱“端口適配器架構(gòu)”,實際上也是一種分層架構(gòu)深夯,只不過由上下或者左右變成了內(nèi)部與外部阿趁。其核心理念就是應(yīng)用通過端口與外部進行交互的。核心的業(yè)務(wù)邏輯(領(lǐng)域模型)與外部資源(數(shù)據(jù)庫等資源)完全隔離处硬,僅通過適配器進行交互小槐,解決了業(yè)務(wù)邏輯與用戶數(shù)據(jù)交錯的問題拇派,很好的實現(xiàn)了前后端分離。

困惑:

  • 在分層架構(gòu)中是否困惑過某些邏輯處理或某些數(shù)據(jù)處理該放在哪一層凿跳?
  • 在分層架構(gòu)中是否困惑過該分多少層件豌?
  • 在分層架構(gòu)中是否困惑過平層和跨層調(diào)用是否合理?

六邊形架構(gòu)

Alistair Cockburn 提出了一種具有對稱特征的架構(gòu)風(fēng)格。在這種架構(gòu)中控嗜,不同的客戶通過平等的方式與系統(tǒng)交互茧彤。比如HTTP客戶,MQ客戶疆栏,它們平等對系統(tǒng)提供輸入曾掂。RedisDB也平等的提供輸出。每個客戶都擁有自己的適配器壁顶,去理解輸入珠洗,比如giniris若专、echo就是http的適配器许蓖。那么內(nèi)部是業(yè)務(wù)系統(tǒng)(領(lǐng)域模型),外部就是輸入和輸出的適配器调衰。重心放在內(nèi)部業(yè)務(wù)邏輯上膊爪,隔離輸入和輸出。如果非要用分層來理解嚎莉,那么六邊形分為內(nèi)層和外層米酬。

Alistair Cockburn提出的六邊形是有Application和Domain的,但現(xiàn)在微服務(wù)體系下Application已經(jīng)沒有存在的必要了趋箩,一個微服務(wù)就是一個Application赃额。

落地的六邊形架構(gòu)圖

那么六邊形和DDD的結(jié)合是如何應(yīng)對上述困惑的琼懊。所有數(shù)據(jù)處理全部由repository適配成實體,邏輯都是領(lǐng)域服務(wù)爬早、聚合哼丈、實體的行為。分多少層和平層筛严、跨層調(diào)用本身也不存在醉旦。

項目目錄

  • domain - 領(lǐng)域模型
    • aggregate - 聚合
    • entity - 實體
    • dto - 傳輸對象
    • po - 持久化對象
    • *.go - 領(lǐng)域服務(wù)
  • adapter - 端口適配器
    • controller - 輸入適配器
    • repository - 輸出適配器
  • server - 服務(wù)端程序入口
    • conf - 配置文件
    • main.go - 主函數(shù)
  • infra - 基礎(chǔ)設(shè)施
    • *go - 基礎(chǔ)設(shè)施組件

domain 領(lǐng)域模型目錄

對應(yīng)六邊形的內(nèi)部,主要放領(lǐng)域服務(wù)service的代碼桨啃。子目錄分為aggregate聚合根目錄车胡、entity實體目錄。dto子目錄是外部輸入輸出對象照瘾。po子目錄是數(shù)據(jù)庫的持久化對象匈棘,這些對象是生成的。

adapter 適配器目錄

對應(yīng)六邊形的外部析命,主要是輸入和輸出的適配器主卫。controller子目錄負責(zé)httpapi輸入,repository子目錄負責(zé)實體的讀寫鹃愤。

外部adapter目錄下的controllerrepository依賴內(nèi)部的domain相關(guān)簇搅,那么domain要使用repository處理po的讀寫呢?這樣不就互相依賴了嗎软吐?后續(xù)會篇幅依賴倒置講解如何外部依賴內(nèi)部瘩将,內(nèi)部依賴抽象。

代碼示例

package controller

import (
    domain "github.com/8treenet/freedom/example/fshop/domain"
)

type Cart struct {
    Worker  freedom.Worker
    CartSev *domain.Cart   //購物車領(lǐng)域服務(wù)凹耙,依賴注入
}

// GetItems 獲取購物車商品列表, GET: /cart/items route.
func (c *Cart) GetItems() freedom.Result {
    userId, err := c.Worker.IrisContext().URLParamInt("userId")
    if err != nil {
        return &infra.JSONResponse{Error: err}
    }

    //適配http的輸入?yún)?shù)userId后調(diào)用領(lǐng)域模型目錄的入口領(lǐng)域服務(wù)
    dto, err := c.CartSev.Items(userId)
    if err != nil {
        return &infra.JSONResponse{Error: err}
    }
    return &infra.JSONResponse{Object: dto}
}
package domain

import (
   //引用倉庫
    "github.com/8treenet/freedom/example/fshop/adapter/repository"
    "github.com/8treenet/freedom/example/fshop/domain/aggregate"
)
func init() {
    freedom.Prepare(func(initiator freedom.Initiator) {
        //綁定創(chuàng)建領(lǐng)域服務(wù)函數(shù)到框架姿现,框架會根據(jù)客戶的使用做依賴倒置和依賴注入的處理。
        initiator.BindService(func() *Cart {
            //創(chuàng)建 Cart領(lǐng)域服務(wù)
            return &Cart{}
        })
        //控制器客戶使用需要明確使用 InjectController
        initiator.InjectController(func(ctx freedom.Context) (service *Cart) {
            initiator.GetService(ctx, &service)
            return
        })
    })
}

// Cart 購物車領(lǐng)域服務(wù).
type Cart struct {
    CartRepo    repository.CartRepo     //購物車倉庫肖抱,這里是依賴倒置的
}

// Items 購物車全部商品項
func (c *Cart) Items(userId int) (items dto.CartItemRes, e error) {
    // 使用 c.CartRepo讀取購物車數(shù)據(jù)
    return
}

// DeleteAll 清空購物車
func (c *Cart) DeleteAll(userId int) (e error) {
    return c.CartRepo.DeleteAll(userId)
}

目錄

  • golang領(lǐng)域模型-開篇
  • golang領(lǐng)域模型-六邊形架構(gòu)
  • golang領(lǐng)域模型-實體
  • golang領(lǐng)域模型-資源庫
  • golang領(lǐng)域模型-依賴倒置
  • golang領(lǐng)域模型-聚合根
  • golang領(lǐng)域模型-CQRS
  • golang領(lǐng)域模型-領(lǐng)域事件

項目代碼 https://github.com/8treenet/freedom/tree/master/example/fshop

PS:關(guān)注公眾號《從菜鳥到大佬》备典,發(fā)送消息“加群”或“領(lǐng)域模型”,加入DDD交流群虐沥,一起切磋DDD與代碼的藝術(shù)熊经!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市欲险,隨后出現(xiàn)的幾起案子镐依,更是在濱河造成了極大的恐慌,老刑警劉巖天试,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件槐壳,死亡現(xiàn)場離奇詭異,居然都是意外死亡喜每,警方通過查閱死者的電腦和手機务唐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門雳攘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枫笛,你說我怎么就攤上這事吨灭。” “怎么了刑巧?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵喧兄,是天一觀的道長。 經(jīng)常有香客問我啊楚,道長吠冤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任恭理,我火速辦了婚禮拯辙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颜价。我一直安慰自己涯保,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布拍嵌。 她就那樣靜靜地躺著遭赂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪横辆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天茄猫,我揣著相機與錄音狈蚤,去河邊找鬼。 笑死划纽,一個胖子當著我的面吹牛脆侮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勇劣,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼靖避,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了比默?” 一聲冷哼從身側(cè)響起幻捏,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎命咐,沒想到半個月后篡九,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡醋奠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年榛臼,在試婚紗的時候發(fā)現(xiàn)自己被綠了伊佃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡沛善,死狀恐怖航揉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情金刁,我是刑警寧澤迷捧,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站胀葱,受9級特大地震影響漠秋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抵屿,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一庆锦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轧葛,春花似錦搂抒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衷笋,卻和暖如春芳杏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辟宗。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工爵赵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泊脐。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓空幻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親容客。 傳聞我的和親對象是個殘疾皇子秕铛,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348