日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一些设计上的基本常识(转载)

發(fā)布時(shí)間:2025/1/21 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一些设计上的基本常识(转载) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:http://code.alibabatech.com/blog/experience_886/software_design_general_knowledge.html

最近給團(tuán)隊(duì)新人講了一些設(shè)計(jì)上的常識(shí),可能會(huì)對(duì)其它的新人也有些幫助,
把暫時(shí)想到的幾條,先記在這里。

1. API與SPI分離

框架或組件通常有兩類客戶,一個(gè)是使用者,一個(gè)是擴(kuò)展者,
API(Application Programming Interface)是給使用者用的,
而SPI(Service Provide Interface)是給擴(kuò)展者用的,
在設(shè)計(jì)時(shí),盡量把它們隔離開,而不要混在一起,
也就是說,使用者是看不到擴(kuò)展者寫的實(shí)現(xiàn)的,
比如:一個(gè)Web框架,它有一個(gè)API接口叫Action,
里面有個(gè)execute()方法,是給使用者用來寫業(yè)務(wù)邏輯的,
然后,Web框架有一個(gè)SPI接口給擴(kuò)展者控制輸出方式,
比如用velocity模板輸出還是用json輸出等,
如果這個(gè)Web框架使用一個(gè)都繼承Action的VelocityAction和一個(gè)JsonAction做為擴(kuò)展方式,
要用velocity模板輸出的就繼承VelocityAction,要用json輸出的就繼承JsonAction,
這就是API和SPI沒有分離的反面例子,SPI接口混在了API接口中,
合理的方式是,有一個(gè)單獨(dú)的Renderer接口,有VelocityRenderer和JsonRenderer實(shí)現(xiàn),
Web框架將Action的輸出轉(zhuǎn)交給Renderer接口做渲染輸出。

2. 服務(wù)域/實(shí)體域/會(huì)話域分離

任何框架或組件,總會(huì)有核心領(lǐng)域模型,比如:
Spring的Bean,Struts的Action,Dubbo的Service,Napoli的Queue等等
這個(gè)核心領(lǐng)域模型及其組成部分稱為實(shí)體域,它代表著我們要操作的目標(biāo)本身,
實(shí)體域通常是線程安全的,不管是通過不變類,同步狀態(tài),或復(fù)制的方式,
服務(wù)域也就是行為域,它是組件的功能集,同時(shí)也負(fù)責(zé)實(shí)體域和會(huì)話域的生命周期管理,
比如Spring的ApplicationContext,Dubbo的ServiceManager等,
服務(wù)域的對(duì)象通常會(huì)比較重,而且是線程安全的,并以單一實(shí)例服務(wù)于所有調(diào)用,
什么是會(huì)話?就是一次交互過程,
會(huì)話中重要的概念是上下文,什么是上下文?
比如我們說:“老地方見”,這里的“老地方”就是上下文信息,
為什么說“老地方”對(duì)方會(huì)知道,因?yàn)槲覀兦懊娑x了“老地方”的具體內(nèi)容,
所以說,上下文通常持有交互過程中的狀態(tài)變量等,
會(huì)話對(duì)象通常較輕,每次請(qǐng)求都重新創(chuàng)建實(shí)例,請(qǐng)求結(jié)束后銷毀。
簡(jiǎn)而言之:
把元信息交由實(shí)體域持有,
把一次請(qǐng)求中的臨時(shí)狀態(tài)由會(huì)話域持有,
由服務(wù)域貫穿整個(gè)過程。

3. 在重要的過程上設(shè)置攔截接口

如果你要寫個(gè)遠(yuǎn)程調(diào)用框架,那遠(yuǎn)程調(diào)用的過程應(yīng)該有一個(gè)統(tǒng)一的攔截接口,
如果你要寫一個(gè)ORM框架,那至少SQL的執(zhí)行過程,Mapping過程要有攔截接口,
如果你要寫一個(gè)Web框架,那請(qǐng)求的執(zhí)行過程應(yīng)該要有攔截接口,
等等,沒有哪個(gè)公用的框架可以Cover住所有需求,允許外置行為,是框架的基本擴(kuò)展方式,
這樣,如果有人想在遠(yuǎn)程調(diào)用前,驗(yàn)證下令牌,驗(yàn)證下黑白名單,統(tǒng)計(jì)下日志,
如果有人想在SQL執(zhí)行前加下分頁包裝,做下數(shù)據(jù)權(quán)限控制,統(tǒng)計(jì)下SQL執(zhí)行時(shí)間,
如果有人想在請(qǐng)求執(zhí)行前檢查下角色,包裝下輸入輸出流,統(tǒng)計(jì)下請(qǐng)求量,
等等,就可以自行完成,而不用侵入框架內(nèi)部,
攔截接口,通常是把過程本身用一個(gè)對(duì)象封裝起來,傳給攔截器鏈,
比如:遠(yuǎn)程調(diào)用主過程為invoke(),那攔截器接口通常為invoke(Invocation),
Invocation對(duì)象封裝了本來要執(zhí)行過程的上下文,并且Invocation里有一個(gè)invoke()方法,
由攔截器決定什么時(shí)候執(zhí)行,同時(shí),Invocation也代表攔截器行為本身,
這樣上一攔截器的Invocation其實(shí)是包裝的下一攔截器的過程,
直到最后一個(gè)攔截器的Invocation是包裝的最終的invoke()過程,
同理,SQL主過程為execute(),那攔截器接口通常為execute(Execution),原理一樣,
當(dāng)然,實(shí)現(xiàn)方式可以任意,上面只是舉例。

4. 重要的狀態(tài)的變更發(fā)送事件并留出監(jiān)聽接口

這里先要講一個(gè)事件和上面攔截器的區(qū)別,攔截器是干預(yù)過程的,它是過程的一部分,是基于過程行為的,
而事件是基于狀態(tài)數(shù)據(jù)的,任何行為改變的相同狀態(tài),對(duì)事件應(yīng)該是一致的,
事件通常是事后通知,是一個(gè)Callback接口,方法名通常是過去式的,比如onChanged(),
比如遠(yuǎn)程調(diào)用框架,當(dāng)網(wǎng)絡(luò)斷開或連上應(yīng)該發(fā)出一個(gè)事件,當(dāng)出現(xiàn)錯(cuò)誤也可以考慮發(fā)出一個(gè)事件,
這樣外圍應(yīng)用就有可能觀察到框架內(nèi)部的變化,做相應(yīng)適應(yīng)。

5. 擴(kuò)展接口職責(zé)盡可能單一,具有可組合性

比如,遠(yuǎn)程調(diào)用框架它的協(xié)議是可以替換的,
如果只提供一個(gè)總的擴(kuò)展接口,當(dāng)然可以做到切換協(xié)議,
但協(xié)議支持是可以細(xì)分為底層通訊,序列化,動(dòng)態(tài)代理方式等等,
如果將接口拆細(xì),正交分解,會(huì)更便于擴(kuò)展者復(fù)用已有邏輯,而只是替換某部分實(shí)現(xiàn)策略,
當(dāng)然這個(gè)分解的粒度需要把握好。

6. 微核插件式,平等對(duì)待第三方

大凡發(fā)展的比較好的框架,都遵守微核的理念,
Eclipse的微核是OSGi, Spring的微核是BeanFactory,Maven的微核是Plexus,
通常核心是不應(yīng)該帶有功能性的,而是一個(gè)生命周期和集成容器,
這樣各功能可以通過相同的方式交互及擴(kuò)展,并且任何功能都可以被替換,
如果做不到微核,至少要平等對(duì)待第三方,
即原作者能實(shí)現(xiàn)的功能,擴(kuò)展者應(yīng)該可以通過擴(kuò)展的方式全部做到,
原作者要把自己也當(dāng)作擴(kuò)展者,這樣才能保證框架的可持續(xù)性及由內(nèi)向外的穩(wěn)定性。

7. 不要控制外部對(duì)象的生命周期

比如上面說的Action使用接口和Renderer擴(kuò)展接口,
框架如果讓使用者或擴(kuò)展者把Action或Renderer實(shí)現(xiàn)類的類名或類元信息報(bào)上來,
然后在內(nèi)部通過反射newInstance()創(chuàng)建一個(gè)實(shí)例,
這樣框架就控制了Action或Renderer實(shí)現(xiàn)類的生命周期,
Action或Renderer的生老病死,框架都自己做了,外部擴(kuò)展或集成都無能為力,
好的辦法是讓使用者或擴(kuò)展者把Action或Renderer實(shí)現(xiàn)類的實(shí)例報(bào)上來,
框架只是使用這些實(shí)例,這些對(duì)象是怎么創(chuàng)建的,怎么銷毀的,都和框架無關(guān),
框架最多提供工具類輔助管理,而不是絕對(duì)控制。

8. 可配置一定可編程,并保持友好的CoC約定

因?yàn)槭褂铆h(huán)境的不確定因素很多,框架總會(huì)有一些配置,
一般都會(huì)到classpath直掃某個(gè)指定名稱的配置,或者啟動(dòng)時(shí)允許指定配置路徑,
做為一個(gè)通用框架,應(yīng)該做到凡是能配置文件做的一定要能通過編程方式進(jìn)行,
否則當(dāng)使用者需要將你的框架與另一個(gè)框架集成時(shí)就會(huì)帶來很多不必要的麻煩,
另外,盡可能做一個(gè)標(biāo)準(zhǔn)約定,如果用戶按某種約定做事時(shí),就不需要該配置項(xiàng)。
比如:配置模板位置,你可以約定,如果放在templates目錄下就不用配了,
如果你想換個(gè)目錄,就配置下。

9. 區(qū)分命令與查詢,明確前置條件與后置條件

這個(gè)是契約式設(shè)計(jì)的一部分,盡量遵守有返回值的方法是查詢方法,void返回的方法是命令,
查詢方法通常是冪等性的,無副作用的,也就是不改變?nèi)魏螤顟B(tài),調(diào)n次結(jié)果都是一樣的,
比如get某個(gè)屬性值,或查詢一條數(shù)據(jù)庫(kù)記錄,
命令是指有副作用的,也就是會(huì)修改狀態(tài),比如set某個(gè)值,或update某條數(shù)據(jù)庫(kù)記錄,
如果你的方法即做了修改狀態(tài)的操作,又做了查詢返回,如果可能,將其拆成寫讀分離的兩個(gè)方法,
比如:User deleteUser(id),刪除用戶并返回被刪除的用戶,考慮改為getUser()和void的deleteUser()。
另外,每個(gè)方法都盡量前置斷言傳入?yún)?shù)的合法性,后置斷言返回結(jié)果的合法性,并文檔化。

總結(jié)

以上是生活随笔為你收集整理的一些设计上的基本常识(转载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。