新聞中心
一、GOlang包設(shè)計
Golang開發(fā)語言并沒有完整實現(xiàn)?OOP?特性,因此我們只能采用包封裝的方式來踐行"高內(nèi)聚,低耦合"的功能設(shè)計。在進行代碼分層管理之后,我們會發(fā)現(xiàn)包命名變得很困難。

主要從事網(wǎng)頁設(shè)計、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、wap網(wǎng)站建設(shè)(手機版網(wǎng)站建設(shè))、成都響應(yīng)式網(wǎng)站建設(shè)公司、程序開發(fā)、微網(wǎng)站、成都小程序開發(fā)等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們在互聯(lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了豐富的成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、網(wǎng)絡(luò)營銷經(jīng)驗,集策劃、開發(fā)、設(shè)計、營銷、管理等多方位專業(yè)化運作于一體,具備承接不同規(guī)模與類型的建設(shè)項目的能力。
大部分時候,我們都習慣按照業(yè)務(wù)領(lǐng)域來進行命名。例如,在?api/dao/service?分層下,我們可能都會同時存在一個以?user?命名的包名(表示用戶相關(guān)的功能邏輯),由于包名相同,在使用的時候卻有極大的困擾。主要的兩個痛點:
- 對于復雜業(yè)務(wù)模塊包名命名困難,例如:業(yè)務(wù)模塊為?
internal_member_privilege?的包名 - 管理過多重復的包名工程效率太低,為了解決重復包名往往會創(chuàng)建很多引用別名( ?
import alias? ) - 工程管理上容易引起包的循環(huán)引用( ?
cycle import? )問題
需要注意的是,Golang語言層面的包循環(huán)依賴檢測其實是很棒的一個特性,它以?package?作為代碼封裝基本單位,使得程序邏輯在?package?之間的執(zhí)行路徑都是單向調(diào)用鏈,可以幫助你梳理出清晰的?package?依賴關(guān)系、編寫出更加健壯性的代碼。
?GoFrame?開發(fā)框架經(jīng)過大量的項目工程實踐,本著從簡約、簡潔、高效、易維護的設(shè)計理念出發(fā),總結(jié)出了一些關(guān)于包設(shè)計和命名約束的最佳實踐,可供參考。
二、對象封裝設(shè)計
在代碼分層設(shè)計之后,我們盡量地減少封裝包的數(shù)量、降低包的復雜度,盡可能采用結(jié)構(gòu)化對象的方式來封裝代碼處理邏輯。
對于業(yè)務(wù)項目而言,業(yè)務(wù)的復雜度會不斷/快速增長,我們期望設(shè)計的模塊復雜度盡可能的小、職責盡可能的單一。而直接使用包封裝設(shè)計會使得每個包管理的資源比較多、單個包復雜度會比較高、并且存在過多同名包問題。因此我們需要將代碼做分層設(shè)計(劃分職責)、將包內(nèi)容做進一步拆分(細化粒度),并將代碼模塊的粒度細化為了"對象"方式進行封裝(這里的"模塊"從?package?細化為了?object?)。目的是使得整體模塊設(shè)計更加的解耦,能夠快速響應(yīng)業(yè)務(wù)發(fā)展的變化。對于業(yè)務(wù)項目而言,我們采用對象封裝設(shè)計后,將會失去包循環(huán)依賴檢測特性帶來的好處,轉(zhuǎn)而由開發(fā)者自行維護對象之間的依賴關(guān)系。
1、業(yè)務(wù)包命名約束
涉及到業(yè)務(wù)對象封裝的代碼層級主要為?controller/service?。每個業(yè)務(wù)包僅對外暴露實例化的對象用于該業(yè)務(wù)領(lǐng)域的具體功能邏輯封裝,同一層級下不同的業(yè)務(wù)領(lǐng)域邏輯通過不同文件來分別管理。包對外的公開對象采用業(yè)務(wù)模塊名稱(大駝峰)來命名,包內(nèi)部的數(shù)據(jù)結(jié)構(gòu)命名采用分層名稱(縮寫)+業(yè)務(wù)模塊名稱(大駝峰)來命名。
| 代碼分層 | 分層名稱縮寫 | 數(shù)據(jù)結(jié)構(gòu)命名示例 |
| controller | c | cUser |
| service | s | sUser |
特別需要強調(diào)的是,在?controller/service?層級中的代碼,有且僅有需要導出的實例化對象才能公開。并且由于同一包下包含多個業(yè)務(wù)領(lǐng)域的數(shù)據(jù)結(jié)構(gòu)定義,因此在命名的時候務(wù)必遵從命名約束,否則容易出現(xiàn)命名沖突。采用單包管理以及實例化對象引用的設(shè)計,整個包對外引用簡潔清晰、內(nèi)部維護緊湊簡便、規(guī)避循環(huán)引用問題。
2、controller層對象封裝
封裝示例:
使用示例:
3、service層對象封裝
封裝示例:
使用示例:
4、dao層對象封裝
?dao?層的對象封裝是通過框架開發(fā)工具維護的,開發(fā)者無需自己定義。
使用示例:
5、對象封裝安全
如果各分層中的封裝對象都是以" 可變變量 "的形式對外暴露使用,因此存在被修改的安全風險。因此大家注意這些公開的對象不要以指針(也盡量不要以接口實例)方式公開這些對象、不要設(shè)置公開屬性(建議通過公開方法暴露內(nèi)部屬性)。
以下是一個錯誤的示例:
以下是一個正確的示例:
三、接口化封裝設(shè)計
富有實戰(zhàn)經(jīng)驗的您一定發(fā)現(xiàn)了,我們上面推崇使用具體化的對象來封裝業(yè)務(wù)邏輯,而沒有一丁點的接口設(shè)計的影子。是的,本著務(wù)實以及成本收益的衡量,我們確實推崇使用具體化的對象來封裝業(yè)務(wù)邏輯,特別是針對于?controller?層以及?dao?層代碼。對于?service?層的代碼,亦是如此。本章節(jié)主要側(cè)重于?service?層代碼的接口化封裝設(shè)計介紹。
1、對象封裝的痛點
?GoFrame?工程設(shè)計的顯著的一個特點是,按照技術(shù)維度進行代碼分層、按照業(yè)務(wù)維度進行對象封裝。這種設(shè)計思想落地的特點就是在同一代碼分層,業(yè)務(wù)模塊是平級的,使得各個業(yè)務(wù)模塊之間隔離性降低了,這也是純粹使用對象化封裝的痛點。比如以下的示例:
可以看到在?service?層下,網(wǎng)絡(luò)模塊(?Network?)訪問資源模塊(?Resource?)時,可以直接訪問到其所有的內(nèi)容,無論是公開還是私有方法,私有的屬性也能訪問甚至修改。同時,雜亂的資源暴露也會使得調(diào)用者感覺困惑,模塊管理和協(xié)作成本比較高。我們更好地隔離資源,方便內(nèi)部模塊之間管理和協(xié)作,這種場景下我們推薦對?service?業(yè)務(wù)模塊使用接口化設(shè)計。
2、service層接口化設(shè)計
將一個項目的業(yè)務(wù)模塊采用對象封裝其實也是有利弊的,不過針對大多數(shù)的項目,都不會接觸到需要挑戰(zhàn)?GoFrame?框架工程化設(shè)計的邊界。在?GoFrame?的整個分層設(shè)計中,?service?層的業(yè)務(wù)邏輯沉淀是最多的,也是最復雜的一部分,在這一部分采用接口化設(shè)計是最有價值的,收益成本比很高。因為?service?層的模塊不僅對外部開放,在?service?層內(nèi)部,模塊與模塊之間的調(diào)用,才是整個業(yè)務(wù)項目中交互最頻繁、設(shè)計最復雜的。降低這一層的維護成本,簡化層級內(nèi)部模塊之間的調(diào)用復雜度,是最有價值和收益的事情。例如上面的例子,我們看看如何來接口化改進。
- 原本的對象封裝
- 采用接口化封裝
接口化只需要兩步即可:
- 增加業(yè)務(wù)模塊的接口定義
- 將原本對象方法返回的對象指針改為返回接口
3、對象封裝到接口切換
大家也應(yīng)該注意到了,對于?service?層的對象化封裝方式,有一些不一樣。在?service?層我們使用了方法返回對象,而不是采用對象變量形式。為什么呢?回答這個問題之前,我們先來看看將資源模塊(?Resource?)進行接口化改進之后,我們在原來的網(wǎng)絡(luò)模塊(?Network?)中是如何使用的:
是的,目標業(yè)務(wù)模塊采用接口化改進之后,對于調(diào)用方來講,使用方式并沒有發(fā)生變化。這便是我們?yōu)槭裁匆?service?中使用方法化封裝對象,而不是直接使用對象變量定義的原因:
- 減少業(yè)務(wù)模塊接口化改進引起的改動,降低維護成本
- 支持從對象封裝調(diào)用無縫切換到接口調(diào)用,調(diào)用端無感知
4、接口化設(shè)計的成本
可以看到,我們增加一層接口定義,其實也增加了一層代碼的維護成本。此外,接口化的代碼對于代碼調(diào)試和定位不太友好,特別是多個層級嵌套的接口而言,想要定位到具體的實現(xiàn)成本較大。對于大部分的項目而言,其實往往不太需要接口化設(shè)計。架構(gòu)設(shè)計中常常出現(xiàn)的悲傷故事之一,就是為了設(shè)計而設(shè)計。
因此,始終本著務(wù)實的設(shè)計原則,在?GoFrame?工程化設(shè)計中,我們推薦項目初期對業(yè)務(wù)邏輯的封裝使用對象封裝的方式,并支持項目根據(jù)業(yè)務(wù)發(fā)展需要從對象封裝設(shè)計到接口化設(shè)計的無縫切換。同時,我們建議接口化設(shè)計中,不要使用多層接口嵌套(即?service?接口方法直接返回實例化對象而不是另一個接口,接口又是接口,以此類推)。
四、注意事項
- 由于對象封裝業(yè)務(wù)模塊的粒度比較細,需要由開發(fā)者來維護業(yè)務(wù)模塊之間的循環(huán)依賴關(guān)系。
- 對于復雜的單倉業(yè)務(wù)項目(沒有意愿采用服務(wù)化拆分),可以考慮前期即對?
service?層采用接口化設(shè)計。 - 在?
service?目錄下的每個業(yè)務(wù)模塊不要都強行放一個代碼文件,可以按照多個文件拆分管理,文件隨著業(yè)務(wù)復雜度的提高可能文件會比較多,屬于正?,F(xiàn)象。 - 如果業(yè)務(wù)模塊本身是極其低耦的,并且模塊邏輯較復雜,可以考慮將其挪到?
service/internal?下使用包管理,并在?service?下保留關(guān)聯(lián)的接口方法即可。?service/internal?目錄存在的意義之一便是為此準備的。
分享名稱:創(chuàng)新互聯(lián)GoFrame教程:GoFrame工程開發(fā)設(shè)計-對象封裝設(shè)計
網(wǎng)站URL:http://www.5511xx.com/article/ccecddo.html


咨詢
建站咨詢
