JS設(shè)計(jì)原則 —— 單一職責(zé)原則

最近看了同事的代碼,感覺(jué)甚是優(yōu)雅,再看看自己的,不禁自慚形穢,為了提高代碼的可擴(kuò)展性和可維護(hù)性等,是時(shí)候好好學(xué)習(xí)一下設(shè)計(jì)模式了。在學(xué)習(xí)設(shè)計(jì)模式之前,需要先看一下設(shè)計(jì)原則,因?yàn)樵O(shè)計(jì)原則是核心思想。就好比練劍,設(shè)計(jì)原則是心訣要領(lǐng),設(shè)計(jì)模式是招式。

我們常說(shuō)的SOLID原則,是包括單一職責(zé)原則、開(kāi)閉原則、里式替換原則、接口隔離原則和依賴(lài)反轉(zhuǎn)原則這五個(gè),與五個(gè)英文字母一一對(duì)應(yīng)。 今天,就先來(lái)看一下單一職責(zé)原則。

什么是單一職責(zé)原則呢?

英文:Single Responsibility Principle,縮寫(xiě)SRP。英文描述:A class or module should have a single reponsibility.(一個(gè)類(lèi)或模塊只負(fù)責(zé)完成一個(gè)功能)

這個(gè)定義很好理解,比如我們開(kāi)發(fā)的時(shí)候要實(shí)現(xiàn)一個(gè)filter組件,不僅實(shí)現(xiàn)了搜索的功能,還把搜索之后的行為定義了出來(lái),例如把搜索結(jié)果作為參數(shù)發(fā)送請(qǐng)求。搜索和發(fā)送請(qǐng)求是兩個(gè)不同的功能,再說(shuō)搜索之后不一定是發(fā)送請(qǐng)求,還可能是其他的行為,這就影響了組件的復(fù)用性,違反了單一職責(zé)原則。

所以對(duì)于類(lèi)或模塊或者函數(shù)等,不要設(shè)計(jì)的大而全,盡量粒度小、功能單一,只包含一個(gè)職責(zé)。如果包含多個(gè)職責(zé),在需求變更的過(guò)程中,就有可能因?yàn)樾薷钠渲幸粋€(gè)職責(zé)而引起其他職責(zé)出現(xiàn)bug。

如何看類(lèi)或方法是否滿(mǎn)足單一職責(zé)原則呢?

單一職責(zé)原則理解起來(lái)很簡(jiǎn)單,我們都知道啥意思,但在具體應(yīng)用中還是有些難度的。不同的應(yīng)用場(chǎng)景、需求階段、業(yè)務(wù)層面,對(duì)同一個(gè)類(lèi)的職責(zé)是否單一,可能會(huì)有不同的判定結(jié)果。

下面通過(guò)一個(gè)例子讓我們一起來(lái)學(xué)習(xí)一下。就拿疫情期間學(xué)生上網(wǎng)課來(lái)說(shuō)吧,StudentInfo類(lèi)大致會(huì)包含以下字段:

class StudentInfo {
  private name: string; // 姓名
  private age: number; // 年齡
  private class: string; // 班級(jí)
  private date: string; // 上課日期
  private onlineStartTime: string; // 網(wǎng)課開(kāi)始時(shí)間
  private onlineEndTime: string; // 網(wǎng)課結(jié)束時(shí)間
  private province; // 省
  private city; // 市
  private region; // 地區(qū)
  private detailedAddress;  // 詳細(xì)地址
}

上面的這些字段能否都?xì)w屬于StudentInfo類(lèi)呢?它符不符合單一職責(zé)原則呢?如果初始這個(gè)系統(tǒng)很簡(jiǎn)單,所有的信息都只是用來(lái)展示而已,那都放到一起也沒(méi)有問(wèn)題,因?yàn)樗鼈円泊_實(shí)都是學(xué)生的信息。后來(lái)有了新的需求,老師想看一看各個(gè)班級(jí)學(xué)生的網(wǎng)課情況,由于要對(duì)網(wǎng)課相關(guān)的信息做更多的處理,就可以把date、onlineStartTime、onlineEndTime字段拆分出來(lái),獨(dú)立成一個(gè)類(lèi)。經(jīng)過(guò)對(duì)網(wǎng)課情況的分析,發(fā)現(xiàn)有些學(xué)生經(jīng)常網(wǎng)課遲到,那是不是某些地區(qū)網(wǎng)絡(luò)不好等情況影響的啊,這就需要地址信息做更多的分析操作,也就可以把地址信息單獨(dú)拆分出來(lái)。

所以,在不同的需求階段或不同的業(yè)務(wù)背景應(yīng)用場(chǎng)景下,對(duì)一個(gè)類(lèi)是否職責(zé)單一的判定也是不同的。我們可以根據(jù)對(duì)業(yè)務(wù)的理解程度,預(yù)測(cè)之后可能會(huì)有哪些功能,來(lái)設(shè)計(jì)職責(zé)單一的類(lèi)或模塊。但很多時(shí)候我們無(wú)法預(yù)測(cè)之后的需求走向,這時(shí)可以先寫(xiě)粗粒度的類(lèi),之后根據(jù)需求變更再不斷重構(gòu),畢竟重構(gòu)也是開(kāi)發(fā)的一部分,可以讓代碼保持可讀性、可維護(hù)性、可擴(kuò)展性等。

現(xiàn)在我們知道判斷類(lèi)是否職責(zé)單一是一個(gè)很靠感覺(jué)的東西,不像算法題有固定的解法,這也是它在實(shí)施的過(guò)程中比較困難的地方。我在《設(shè)計(jì)模式之美》專(zhuān)欄中看到了王爭(zhēng)老師給出的一些判斷指標(biāo)很具有指導(dǎo)意義,出現(xiàn)下面的情況就可能說(shuō)明類(lèi)的設(shè)計(jì)不滿(mǎn)足單一職責(zé)原則:

  • 類(lèi)中的代碼行數(shù)、函數(shù)或?qū)傩赃^(guò)多,會(huì)影響代碼的可讀性和可維護(hù)性
  • 類(lèi)依賴(lài)的其他類(lèi)過(guò)多,或依賴(lài)類(lèi)的其他類(lèi)過(guò)多,不符合高內(nèi)聚、低耦合的思想
  • 私有方法過(guò)多,就要考慮能否將私有方法獨(dú)立到新的類(lèi)中,設(shè)置為public,供更多的類(lèi)使用,提高代碼復(fù)用性。
  • 比較難給類(lèi)起一個(gè)合適的名字,很難用一個(gè)業(yè)務(wù)名詞概括,或只能用籠統(tǒng)的詞語(yǔ)來(lái)命名,就說(shuō)明類(lèi)的職責(zé)可能不夠清晰
  • 類(lèi)中大量的方法都是集中操作類(lèi)的某幾個(gè)屬性,就可以考慮將這幾個(gè)屬性和對(duì)應(yīng)的方法拆分出來(lái)。

為了滿(mǎn)足單一職責(zé)原則,是不是要把方法或類(lèi)設(shè)計(jì)的越單一越好呢?

大家都聽(tīng)說(shuō)過(guò)“過(guò)猶不及”這個(gè)詞,什么事都得有個(gè)度,如果為了追求單一職責(zé)原則而過(guò)度拆分,也會(huì)影響代碼的可讀性和可維護(hù)性。

不管使用什么設(shè)計(jì)原則和模式,提高代碼的可讀性、可維護(hù)性、可擴(kuò)展性、復(fù)用性,使代碼高內(nèi)聚、低耦合才是目的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容