W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
設(shè)計(jì)軟件有兩種方法:一種是簡(jiǎn)單到明顯沒(méi)有缺陷,另外一種復(fù)雜到缺陷不那么明顯。 --托尼.霍爾
在軟件工程這一學(xué)科和行業(yè)里,關(guān)于軟件工程的解說(shuō)有很多。有人說(shuō)開發(fā)是一門藝術(shù);有人說(shuō)開發(fā)是一種技藝;也有人說(shuō)開發(fā)是一門哲學(xué)。但個(gè)人認(rèn)同從實(shí)用主義和理性的角度去理解。
例如一個(gè)框架,我們之所以認(rèn)為它好是因?yàn)槲覀儼l(fā)現(xiàn)這個(gè)框架遵循了編程規(guī)范、適當(dāng)?shù)厥褂昧嗽O(shè)計(jì)模式、巧妙地結(jié)合了設(shè)計(jì)原則、有著穩(wěn)定的依賴、代碼復(fù)雜度低、并且有著很高代碼覆蓋率的單元測(cè)試等等。
也就是說(shuō),好的框架都是可以被解釋的。既然可以被解釋量化,也就可以學(xué)習(xí)、參考和借鑒。
關(guān)于共性和可變性分析,在《設(shè)計(jì)模式解析》一書中有著非常到位的講解。
CVA是一種很容易的理念,按我的理解即: 抽離共性、隔離變化 。有點(diǎn)類似易經(jīng)里面的“變”與“不變”。
誠(chéng)然,在過(guò)去的教育中(包括大學(xué)在內(nèi)的),對(duì)于軟件開發(fā)都著重談?wù)撁嫦驅(qū)ο箝_發(fā),即OOD,以致于很多人都對(duì)面向?qū)ο箝_發(fā)產(chǎn)生了很大的誤解。而這種誤解所帶來(lái)的實(shí)際情況就是: 我們都在進(jìn)行面向?qū)ο箝_發(fā),但卻是標(biāo)準(zhǔn)呆板的面向?qū)ο箝_發(fā),缺少生氣,缺少活力 。
很多人,都沒(méi)有把我們開發(fā)人員作為專業(yè)人士看待,甚至連我們自己都否認(rèn)我們是專業(yè)的。所以很多時(shí)候當(dāng)產(chǎn)品提出需求時(shí),我們提供的開發(fā)周期往往會(huì)被外界以講價(jià)的方式削減。何以?為什么醫(yī)生給出的手術(shù)時(shí)間病人沒(méi)有討價(jià)呢?因?yàn)楹芎?jiǎn)單,在病人的眼里,醫(yī)生是專業(yè)的。
若我們也想達(dá)到專業(yè)的層次時(shí),何以為?學(xué)習(xí)、思考和實(shí)踐,我認(rèn)為至少這三者是必不可少的。
所以,當(dāng)我們?cè)趯?duì)PhalApi進(jìn)行設(shè)計(jì)時(shí),我們進(jìn)行了一次又一次地醞釀、嘗試、思考。我們?cè)谒伎迹哼@些功能是否真的會(huì)在實(shí)際項(xiàng)目中被使用?開發(fā)人員是否可能很好地進(jìn)行擴(kuò)展?此種決策是否便于單元測(cè)試、從思路上減少代碼異味?。。。
我們謹(jǐn)記敏捷開發(fā),不過(guò)度設(shè)計(jì)。但我們也確實(shí)需要一種思想上的指導(dǎo)。正好,我們看到了 共性和可變性的分析(commonality and variability analysis, CVA) 。
引用一下《設(shè)計(jì)模式解析》一書中的圖表:
在這種理念的指導(dǎo)下,我們會(huì)更愿意將接口開發(fā)過(guò)程的共性抽離統(tǒng)一起來(lái),而可變性部分的則可以由開發(fā)人員根據(jù)不同的項(xiàng)目情況進(jìn)行快速定制實(shí)現(xiàn)。
除了常談及到的“低耦合、高內(nèi)聚”外,在對(duì)代碼進(jìn)行靜態(tài)分析和衡量其可維護(hù)度時(shí),還有一個(gè)值得注意的值,即:不穩(wěn)定的度量。
不穩(wěn)定的度量可以根據(jù)以下公式計(jì)算獲得:
I = 離心耦合 / (離心耦合 + 向心耦合)
因此從宏觀上,我們的代碼結(jié)構(gòu),從上層到下層,應(yīng)該向著穩(wěn)定的方向遞增,也就是說(shuō)越底層越應(yīng)穩(wěn)定。對(duì)應(yīng) 穩(wěn)定依賴原則的規(guī)則(SDP),包之間的依賴應(yīng)該朝著穩(wěn)定的方向:不穩(wěn)定的包應(yīng)該依賴于更穩(wěn)定的包。
又結(jié)合不穩(wěn)定性與抽象分布圖,我們PhalApi框架的代碼 應(yīng)該大部分分布在上圖中的抽象穩(wěn)定區(qū)以實(shí)現(xiàn)框架高層的建設(shè)、少部分分布在具體不穩(wěn)定區(qū)以提供一些基礎(chǔ)的功能 。
在框架的特性中,包括:可重用、IoC Container以及SOLID五條原則的運(yùn)用等。這里就部分SOLID原則的運(yùn)用簡(jiǎn)單說(shuō)明一下。
這是我們一直都堅(jiān)持遵守的原則,因?yàn)?,我們也?jiān)持 短而美 的寫法, 致力于編寫優(yōu)雅的代碼、編寫人容易理解的代碼 。
我們首先希望的是在進(jìn)行接口開發(fā)過(guò)程中,當(dāng)需要新增一個(gè)接口時(shí)是開放的,對(duì)已有的響應(yīng)調(diào)用流程是封閉的。即我們只需要實(shí)現(xiàn)新接口邏輯即可,不需要改動(dòng)其他過(guò)程的調(diào)用。因此在OCP原則的指導(dǎo)下,我們通過(guò)結(jié)合工廠方法封裝了對(duì)接口的初始化和調(diào)用。
PhalApi框架,最大的特色莫過(guò)于 它提供了一種如何快速進(jìn)行接口開發(fā)的機(jī)制,但它不強(qiáng)制你使用不必要的功能,甚至它還鼓勵(lì)你通過(guò)它來(lái)嘗試研發(fā)自己的框架 。更進(jìn)一步,PhalApi引入了新穎明確的概念,一如服務(wù)。我們把客戶端調(diào)用的接口稱之為接口服務(wù),把服務(wù)端用到的資源稱之為資源服務(wù)。對(duì)于后者,PhalApi提供了靈活的DI機(jī)制,以支持各項(xiàng)目定制化的開發(fā)。
顯然,到目前為止,從核心架構(gòu)圖所折射出PhalApi的結(jié)構(gòu)和代碼是如此的 簡(jiǎn)單明了、統(tǒng)一規(guī)范。至少我是這么認(rèn)為的,也是一直這樣努力的。
從上圖的核心架構(gòu)圖可以看出,中間紅色部分的DI處于匯點(diǎn)位置,提供各種資源服務(wù)的定位、創(chuàng)建、管理和提供。
而左上角的代碼示例則表達(dá)本系統(tǒng)框架運(yùn)行的主流程: 創(chuàng)建一個(gè)接口實(shí)例,運(yùn)行響應(yīng)。
右上解黃色部分則為多變的接口應(yīng)用開發(fā)的代碼,這里特意羅列了兩組接口,意在表明可以在此框架下掛靠多套接口。
最下面是接口開發(fā)過(guò)程中所用到的各種基礎(chǔ)設(shè)施和技術(shù),如日志、配置讀取、緩存、加密、請(qǐng)求和響應(yīng)等。同樣,除各應(yīng)用項(xiàng)目中形式多變的接口開發(fā)外,這塊的底層技術(shù)亦支撐不一而足的需求。因?yàn)?,PhalApi只是作了共性的抽離,即提供一級(jí)抽象且穩(wěn)定的接口或者抽象類,以約定規(guī)約視角中接口的函數(shù)簽名,不作過(guò)多的具體實(shí)現(xiàn)。同時(shí)以DI作為輔助,支持快速擴(kuò)展。
和其他框架不同,除了有文檔對(duì)基本使用有說(shuō)明外,我們還提供了我們框架核心的設(shè)計(jì)和思想,以便大家洞明其中的原理從而進(jìn)一步優(yōu)化擴(kuò)展。
這里,扼要說(shuō)明一下PhalApi框架中接口請(qǐng)求背后的核心執(zhí)行流程。
從上圖的時(shí)序圖中可以看出,在PhalApi中,一個(gè)接口的請(qǐng)求處理,只要分為兩個(gè)環(huán)節(jié): 接口服務(wù)初始化 和 接口服務(wù)調(diào)用 。
在Web Service中,往往需要對(duì)服務(wù)進(jìn)行注冊(cè)發(fā)布后,才能開放請(qǐng)求。這里免去這一層,但遵循 創(chuàng)建和使用分離 的原則,我們將接口服務(wù)的初始化進(jìn)行了封裝,以便可以統(tǒng)一進(jìn)行初始化、異常處理和一些權(quán)限ACL的控制
,甚至接口訪問(wèn)的統(tǒng)計(jì)等操作,更為重要的是接口開發(fā)人員可以進(jìn)行無(wú)緒開發(fā),而不需要過(guò)多知道如何合法創(chuàng)建接口服務(wù)。
在1.2. 步驟中,UML時(shí)序圖中的::generateService()表示對(duì)靜態(tài)函數(shù)的調(diào)用,即對(duì)應(yīng)代碼:
PhalApi_ApiFactory::generateService();
隨后,可以看到(假設(shè)我們這次請(qǐng)求的服務(wù)為:?service=Demo.DoSth),我們創(chuàng)建了一個(gè)指定接口的實(shí)例(此接口類須繼承于PhalApi_Api基類),并以變量a返回實(shí)例。
如果請(qǐng)求的服務(wù)非法,則會(huì)以 400非法請(qǐng)求 返回給客戶端。而正確創(chuàng)建接口服務(wù)a后,則會(huì)進(jìn)行接口的初始化,其中有接口參數(shù)規(guī)則的解析和注冊(cè)了過(guò)濾器服務(wù)后的檢測(cè)操作。
當(dāng)這一系列的操作都成功執(zhí)行后,我們將會(huì)得到一個(gè)接口服務(wù)實(shí)例a返回。
因此,在接口服務(wù)的創(chuàng)建過(guò)程中,我們沒(méi)有過(guò)多地限制,而是預(yù)留了很大的空間給到接口項(xiàng)目定制開發(fā)。
至此,接口服務(wù)的創(chuàng)建完成。
在完成復(fù)雜的創(chuàng)建工作后,客戶端(備注:這里指的是服務(wù)端開發(fā)的開發(fā)客戶端)只需要簡(jiǎn)單調(diào)用需要進(jìn)行的操作即可。
而這一塊,則需要接口項(xiàng)目具體開發(fā)實(shí)現(xiàn),也是我們項(xiàng)目級(jí)的核心部分。
在獲取接口服務(wù)的背后,我們建議結(jié)合領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的理念,對(duì)項(xiàng)目代碼進(jìn)行這樣的層級(jí)劃分:
最后,是我們客戶端關(guān)心的返回格式。 默認(rèn)情況下,我們都是以JSON格式返回的,但仍然可以輕松支持其他格式的返回,如JSONP、XML等。只需要簡(jiǎn)單地開發(fā)實(shí)現(xiàn),然后重新注冊(cè)即可。
至此,接口服務(wù)的調(diào)用完畢。
當(dāng)使用一個(gè)開源框架時(shí),我們既喜歡其強(qiáng)大的一面,但矛盾的同時(shí)我們又害怕其中的復(fù)雜性,原因莫過(guò)于:學(xué)習(xí)成本高、出現(xiàn)問(wèn)題時(shí)怕駕馭不了。
而在這里,在PhalApi這里,這一切都是這么簡(jiǎn)單,簡(jiǎn)單地又如此明了。
當(dāng)需要進(jìn)行資源服務(wù)的擴(kuò)展時(shí),我們可以:
實(shí)現(xiàn)指定資源服務(wù)在規(guī)約視角約定的接口,假設(shè)我們需要用文件來(lái)當(dāng)作新的緩存存儲(chǔ)。則需:
class MyCache_File implements PhalApi_Cache {
public function set($key, $value, $expire = 600) {
//...
}
public function get($key) {
//...
}
public function delete($key) {
//...
}
}
當(dāng)實(shí)現(xiàn)自己的功能后,只需要簡(jiǎn)單地在入口文件重新注冊(cè)即可。如:
DI()->cache = new MyCache_File();
最后,另人興奮的是,原來(lái)全部的調(diào)用代碼都不需要改動(dòng),即可享受后期調(diào)整升級(jí)后的新功能!完全避免了曾經(jīng)那種“牽一發(fā)而動(dòng)全身”的痛苦。并且,定制開發(fā)出來(lái)的實(shí)現(xiàn)類,還可以跨越業(yè)務(wù)在其他項(xiàng)目中共用。
這不正是我們常常所說(shuō)的代碼重用嗎?而如今,我們很優(yōu)雅地做到了!
然而,我們?cè)趯?shí)際開發(fā)中收獲到的遠(yuǎn)遠(yuǎn)不是代碼重用這么簡(jiǎn)單,而是一種更好的開發(fā)實(shí)踐。因?yàn)橥ㄟ^(guò)DI使得創(chuàng)建和使用分離,所以我們可以讓高級(jí)的開發(fā)同學(xué)實(shí)現(xiàn)服務(wù)功能的開發(fā),然后再提供給普通的開發(fā)同學(xué)使用,新手亦然,因?yàn)閷?duì)他們來(lái)說(shuō):會(huì)用就行。當(dāng)然,對(duì)于高級(jí)的同學(xué),還應(yīng)該遵循開發(fā)的最佳實(shí)踐,堅(jiān)持單元測(cè)試,以保證我們提供了可靠的接口(廣義上的接口,非HTTP請(qǐng)求的接口)給我們的“客戶端”使用。
若如此,我們的開發(fā)合作豈不是很更合理、更明朗、更愉快?哈哈,我想是的。
作為一個(gè)框架,我們應(yīng)當(dāng)以發(fā)散的方式去設(shè)計(jì);但為了能為應(yīng)用提供可用的功能,我們又應(yīng)當(dāng)以收斂的方式去實(shí)現(xiàn)。
如果我們提供的功能不足以滿足大部分主流的業(yè)務(wù)場(chǎng)景,那么我們至少需要提供可擴(kuò)展的空間。
正是出于這樣的考慮,我們虔誠(chéng)地引入了DI。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: