軟件設(shè)計(jì)SOLID原則中有一個(gè)最基礎(chǔ)的原則就是單一職責(zé)原則,我想絕大部分的程序員都知道,而且都理解它的意思,甚至覺(jué)得很簡(jiǎn)單。但是往往“看懂”和“會(huì)用”是兩回事,而“用好”更是難上加難。好比我們項(xiàng)目,一開(kāi)始一直和大家強(qiáng)調(diào)類的單一職責(zé),隨著業(yè)務(wù)不斷發(fā)展,不同的同事都往這個(gè)類“添磚加瓦”,最終導(dǎo)致一個(gè)類5000多行,如下圖所示,連IDE都受不了,變得卡頓,可想后面維護(hù)成本有多大了,究竟為什么會(huì)這樣呢?又該如何解決呢?
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了浮梁免費(fèi)建站歡迎大家使用!什么是單一職責(zé)原則(SRP)?歡迎關(guān)注微信公眾號(hào)「JAVA旭陽(yáng)」交流和學(xué)習(xí)
單一職責(zé)原則的英文是Single Responsibility Principle
,縮寫為SRP
。這個(gè)原則的英文描述是這樣的:A class or module should have a single reponsibility
。如果我們把它翻譯成中文,那就是:一個(gè)類或者模塊只負(fù)責(zé)完成一個(gè)職責(zé)(或者功能)。簡(jiǎn)單來(lái)說(shuō),一個(gè)類只負(fù)責(zé)完成一個(gè)職責(zé)或者功能。也就是說(shuō),不要設(shè)計(jì)大而全的類,要設(shè)計(jì)粒度小、功能單一的類。
上例子,比如,一個(gè)類里既包含訂單的一些操作,又包含用戶的一些操作。而訂單和用戶是兩個(gè)獨(dú)立的業(yè)務(wù)領(lǐng)域模型,我們將兩個(gè)不相干的功能放到同一個(gè)類中,那就違反了單一職責(zé)原則。為了滿足單一職責(zé)原則,我們需要將這個(gè)類拆分成兩個(gè)粒度更細(xì)、功能更加單一的兩個(gè)類:訂單類和用戶類。
如何判斷類是否夠“專一”?聽(tīng)起來(lái)類的單一職責(zé)很簡(jiǎn)單,很容易區(qū)分清楚,就比如上面的例子中的用戶和訂單,那為什么我們?cè)陂_(kāi)發(fā)過(guò)程中還是容易把一個(gè)類寫的越來(lái)越大呢?好吧我們項(xiàng)目中的這個(gè)5000多行的類,實(shí)際上都是和“指標(biāo)”這個(gè)領(lǐng)域模型的相關(guān)操作,所以對(duì)于大部分同事很難去界定出來(lái)哪些功能歸為一類,屬于一個(gè)職責(zé)范圍之內(nèi)的,既然搞不清楚,那么我就都寫一起好了,大部分都是這樣去寫代碼的。
這邊再用一個(gè)實(shí)際的例子解釋下這種模糊的情況。
比如下面的UserInfo
類的設(shè)計(jì)是否滿足單一職責(zé)原則呢?
public class UserInfo {
private long userId;
private String username;
private String email;
private String telephone;
private long createTime;
private long lastLoginTime;
private String avatarUrl;
private String provinceOfAddress; // 省
private String cityOfAddress; // 市
private String regionOfAddress; // 區(qū)
private String detailedAddress; // 詳細(xì)地址
// ... 省略其他屬性和方法...
}
UserInfo
類包含的信息都是用戶相關(guān)的行為,滿足單一職責(zé)原則。UserInfo
類中,所占的比重比較高,可以繼續(xù)拆分成獨(dú)立的UserAddress
類,UserInfo
只保留除Address
之外的其他信息,拆分之后的兩個(gè)類的職責(zé)更加單一。其實(shí)是否滿足單一職責(zé)原則,需要結(jié)合具體的業(yè)務(wù)場(chǎng)景,如果你現(xiàn)在是社交場(chǎng)景中,地址單純用來(lái)展示使用,那么它就是符合單一職責(zé)原則。如果在電商場(chǎng)景中,地址就要訂單、物流等信息中出現(xiàn),那么就要做進(jìn)一步拆分。
所以說(shuō),不同的應(yīng)用場(chǎng)景、不同階段的需求背景下,對(duì)同一個(gè)類的職責(zé)是否單一的判定,可能都是不一樣的。在某種應(yīng)用場(chǎng)景或者當(dāng)下的需求背景下,一個(gè)類的設(shè)計(jì)可能已經(jīng)滿足單一職責(zé)原則了,但如果換個(gè)應(yīng)用場(chǎng)景或著在未來(lái)的某個(gè)需求背景下,可能就不滿足了,需要繼續(xù)拆分成粒度更細(xì)的類。
小結(jié):
評(píng)價(jià)一個(gè)類的職責(zé)是否"專一",我們并沒(méi)有一個(gè)非常明確的、可以量化的標(biāo)準(zhǔn),可以說(shuō),這是件非常主觀、仁者見(jiàn)仁智者見(jiàn)智的事情。實(shí)際上,在真正的軟件開(kāi)發(fā)中,我們也沒(méi)必要過(guò)于未雨綢繆,過(guò)度設(shè)計(jì)。所以,我們可以先寫一個(gè)粗粒度的類,滿足業(yè)務(wù)需求。隨著業(yè)務(wù)的發(fā)展,如果粗粒度的類越來(lái)越龐大,代碼越來(lái)越多,這個(gè)時(shí)候,我們就可以將這個(gè)粗粒度的類,拆分成幾個(gè)更細(xì)粒度的類,進(jìn)行持續(xù)重構(gòu)。
該具體怎么做?上面判定一個(gè)類是否具備單一職責(zé),還是比較模糊、主觀,那么有沒(méi)有具體地、可執(zhí)行的標(biāo)準(zhǔn)來(lái)判斷呢?比如以我們的項(xiàng)目為例:
UserInfo
例子中,如果一半的方法都是在操作address
信息,那就可以考慮將這幾個(gè)屬性和對(duì)應(yīng)的方法拆分出來(lái)。本文探討了類的單一職責(zé)原則,如何判定一個(gè)類是否"專一",以及具體該如何做。不僅僅是類,我們可以進(jìn)行引申,你的方法足夠單一嗎?你的模塊或者服務(wù)足夠單一嗎?另外,很關(guān)鍵的一點(diǎn)就是你在寫代碼的時(shí)候,一定要?jiǎng)幽X子,思考這段代碼寫這里合適嗎?,為這段代碼找到一個(gè)真正屬于它的“家”。多多思考,那么你一定會(huì)變得越來(lái)越專業(yè)。
歡迎關(guān)注微信公眾號(hào)「JAVA旭陽(yáng)」交流和學(xué)習(xí)
更多學(xué)習(xí)資料請(qǐng)移步:程序員成神之路
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧