關(guān)于ADM思想主要是指在API開發(fā)中使用API,Domain和Model三層結(jié)構(gòu),PhalGo從PhalApi中學(xué)習(xí)并且推崇這種設(shè)計(jì)模式,這種模式的好處在于分工明確,業(yè)務(wù)復(fù)用,數(shù)據(jù)復(fù)用可以減少復(fù)雜業(yè)務(wù)重復(fù)的代碼量,很多框架關(guān)心性能,而不關(guān)心人文;很多項(xiàng)目關(guān)心技術(shù),而不關(guān)注業(yè)務(wù)。ADM設(shè)計(jì)就是從業(yè)務(wù)的角度出發(fā)建立的開發(fā)規(guī)范.
Api層可以理解為是請求開始結(jié)束以及組合業(yè)務(wù)的地方,主要負(fù)責(zé)以下幾件事情:
我們可以看一個獲取用戶詳情接口的例子:
func (this *User_Api)GetUserInfo() echo.HandlerFunc {
return func(c echo.Context) error {
Request := phalgo.Requser{Context:c}
Response := phalgo.Response{Context:c}
defer Request.ErrorLogRecover()
//獲取請求參數(shù)
id := Request.GetParam("id").GetInt()
//拼接領(lǐng)域?qū)訕I(yè)務(wù)
user, err := this.Domain.User.GetUserInfo(id)
if err != nil {
return Response.RetError(err, 400)
}
//返回結(jié)果
return Response.RetSuccess(user)
}
}
(1)Api接口層應(yīng)該做:
(2)Api接口層不應(yīng)該做:
Domain可以稱之為領(lǐng)域?qū)?是ADM(Api-Domain-Model)分層中的橋梁,主要負(fù)責(zé)處理業(yè)務(wù)規(guī)則。Domain層存在的目錄是為了把復(fù)雜業(yè)務(wù)拆分成一個一個小模塊然后組織起來實(shí)現(xiàn)復(fù)雜的業(yè)務(wù),從而達(dá)到代碼復(fù)用,拆分復(fù)雜業(yè)務(wù)的作用.
場景:我們在傳統(tǒng)MVC開發(fā)的時候,使用控制器來處理業(yè)務(wù),我們可能會寫很多的重復(fù)代碼來驗(yàn)證用戶提交的信息是否ok,比如完善信息的時候驗(yàn)證郵箱,在修改用戶信息的時候也要驗(yàn)證修改的郵箱,在管理的時候去編輯一個用戶的時候也可能在去驗(yàn)證郵箱,這個時候我們的驗(yàn)證邏輯代碼已經(jīng)重復(fù)寫在了3個地方,如果有一個需求加入了電話號碼,那么你需要在3個地方加上對電話號碼的驗(yàn)證邏輯
場景一并不難以遇到,而且在復(fù)雜的業(yè)務(wù)情況下重復(fù)使用的業(yè)務(wù)邏輯會更多,如果我們使用了Domain來處理用戶修改前的驗(yàn)證那么我們只需要修改這個驗(yàn)證邏輯加上對電話號碼的驗(yàn)證,那么所有需要驗(yàn)證用戶信息的地方就會全部生效,而不用去做重復(fù)的工作并且避免遺漏的風(fēng)險
下面是我們獲取User詳情的Domain層的實(shí)現(xiàn),它不僅僅只是可以用在獲取用戶詳情也可以用來驗(yàn)證用戶ID是否有效,增加代碼復(fù)用性減少修改代價
func (this *Domain_User)GetUserInfo(id int)(Model.User,error) {
user, err := this.Model.User.GetInfoById(id)
if err != nil {
return user, errors.New("UserInfo There is no")
}
return user,nil
}
一個函數(shù)如果超過了一屏那將會影響到閱讀者的理解,使用領(lǐng)域?qū)硬鸱直恐氐臉I(yè)務(wù)可以很好的解決這個問題
Model層想必不用說了,就是和數(shù)據(jù)庫通訊獲取數(shù)據(jù),Model層是單純的不帶任何業(yè)務(wù)只是簡單的獲取數(shù)據(jù)庫數(shù)據(jù),我們看一段Model層代碼:
type User struct {
Id int `gorm:"column:aId"`
Name string `gorm:"column:name"`
Passwd string `gorm:"column:passwd"`
Email string `gorm:"column:email"`
}
func (User) TableName() string {
return "user"
}
func (this *User)GetInfoById(id int) (User, error) {
User := User{}
err := phalgo.GetORM().Where("id = ?", id).First(&User).Error
return User, err
}
注意:Model層只應(yīng)該獲取數(shù)據(jù)然后結(jié)束關(guān)于沒有獲取到數(shù)據(jù),獲取出錯等情況拋出到Domain層進(jìn)行處理,這樣可以增加靈活性,比如通過用戶名是否重復(fù)和通過用戶名稱獲取ID,一個返回存在才算異常,一個返回不存在才算異常,具體更具業(yè)務(wù)不同體現(xiàn)也不同,所以Model層處理并不合適
整體上講根據(jù)從Api接口層、Domain領(lǐng)域?qū)釉俚組odel數(shù)據(jù)源層的順序進(jìn)行開發(fā)。
在開發(fā)過程中,需要注意不能越層調(diào)用也不能逆向調(diào)用,即不能Api調(diào)用Model。而應(yīng)該是上層調(diào)用下層,或者同層級調(diào)用,也就是說,我們應(yīng)該:
為了更明確調(diào)用的關(guān)系,以下調(diào)用是 錯誤 的:
這樣的約定,便于我們形成統(tǒng)一的開發(fā)規(guī)范,降低學(xué)習(xí)維護(hù)成本。
比如需要添加緩存,我們知道應(yīng)該定位到Model層數(shù)據(jù)源進(jìn)行擴(kuò)展;若發(fā)現(xiàn)業(yè)務(wù)規(guī)則處理不當(dāng),則應(yīng)該進(jìn)入Domain層探其究竟;如果需要對接口的參數(shù)進(jìn)行調(diào)整,即使是新手也知道應(yīng)該找到對應(yīng)的Api文件進(jìn)行改動。
更多建議: