代碼審查關(guān)注什么:SOLID 原則

在今天的文章中址芯,我們將更仔細的討論代碼本身的設(shè)計,特別檢查是否遵循了良好的面向?qū)ο笤O(shè)計實踐瓢姻。和我們已經(jīng)討論過的其他方面一樣墩莫,不是所有的團隊都會將 SOLID 原則列為最重要的檢查項,但是如果你在嘗試遵循 SOLID 原則羞福,或者在嘗試將你的代碼往這方面發(fā)展惕蹄,這里有一些提示可能對你有幫助。

SOLID 是什么治专?

SOLID 原則是面向?qū)ο笤O(shè)計和編程的5個核心原則卖陵。本文的目的不是詳細講解 SOLID 原則是什么或者深入討論為什么你要遵循這些原則,而是指出在代碼審查中怎么發(fā)現(xiàn)沒有遵循這些原則的味道张峰。

SOLID 代表:

單一功能原則(SRP)

在修改一個類時永遠都應(yīng)該只有一個理由

這一點在單次代碼審查時可能比較難發(fā)現(xiàn)泪蔫。根據(jù)這個規(guī)則的定義,作者在修改代碼是有(或者應(yīng)該有)一個理由--解決 bug喘批,添加一個新功能撩荣,代碼重構(gòu)。

你需要關(guān)注一個類里面哪些方法可能會同時修改谤祖,以及哪些方法不會因為其他方法的修改而修改婿滓。例如:

通過 Upsource 的兩欄差異比較會發(fā)現(xiàn) TweetMonitor 中添加了一個新功能,在一些用戶界面的發(fā)帖排行榜繪制前面10個發(fā)帖者的能力粥喜。這看起來是合理的凸主,因為它使用了 onMessage 方法搜集好的數(shù)據(jù),但是有跡象表明它破壞了 SRP 原則额湘。OnMessagegetTweetMessageFromFullTweet 方法都是關(guān)于接收并解析一條 Twitter 消息卿吐,然而 draw 方法為了UI展示重新獲取相關(guān)數(shù)據(jù)旁舰。

代碼審查者應(yīng)該標記出這兩個職責,并且之后和作者一起討論一個更好的方式來分割這兩個功能:也許可以將 Twitter 字符串的解析移到一個不同的類中嗡官;或者創(chuàng)建一個不同的類來負責提供發(fā)帖排行榜箭窜。

開閉原則(OCP)

軟件實體(類,模塊衍腥,函數(shù)等等)應(yīng)該對擴展開放磺樱,但是對修改封閉。

作為審查者婆咸,如果發(fā)現(xiàn)通過一系列的 if 語句來檢查類型竹捉,你應(yīng)該意識到破壞了開閉原則。

如果你在審查上面的代碼尚骄,你應(yīng)該很清楚的意識到块差,如果一種新的 Event 類型添加到系統(tǒng)中,那么新的類型創(chuàng)建者為了處理新添加的類型倔丈,它也許必須添加另一個 else 語句到這個方法中憨闰。

使用多態(tài)來替換這些 if 可能會好一些:

和往常一樣,這個問題不止一個解決方法需五,但關(guān)鍵是將復(fù)雜的 if/elseinstanceof 檢查去掉鹉动。

里氏替換原則(LSP)

使用了基類引用的函數(shù),在不知道基類子類的情況下宏邮,也能夠使用子類的對象

發(fā)現(xiàn)破壞這一規(guī)則的簡單方法就是關(guān)注顯式的類型轉(zhuǎn)換训裆。如果你必須將一個對象轉(zhuǎn)換為其他類型,那么你并沒有“在不知道子類信息的情況下”使用基類蜀铲。

在檢查 LSP 的以下兩個條件時,會發(fā)現(xiàn)更多微妙的破壞 LSP:

想象一下,例如我們有一個抽象類 Order族扰,它有一系列子類 - BookOrder厌丑,ElectronicsOrder 等等。Order 類的
PlaceOrder 方法接收 Warehouse 參數(shù)渔呵,并以此修改倉庫中的庫存水平:

現(xiàn)在假設(shè)我們引入了新的電子禮品卡怒竿,這個只需要往錢包里添加余額就可以,不需要實際的庫存扩氢。如果用 GiftCardOrder 類來實現(xiàn)電子禮品卡耕驰,placeOrder 方法就不必使用 warehouse 參數(shù):

這看起來像是合理的使用繼承,但事實上你是希望使用 GiftCardOrder 類的代碼能夠像使用其他類那樣使用它录豺,即你希望所有的子類都能通過測試:

但是這個測試并通不過朦肘,因為 GiftCardOrder 有不同的訂購行為饭弓。如果你在審查這一類代碼,確認這里使用繼承是否合理--也許訂購行為可以通過組合而不是繼承來插入媒抠。

接口分離原則(ISP)

多個明確的客戶端接口要好于一個通用的接口

如果代碼中有接口定義了很多個方法弟断,那么很容易確認它破壞了這一規(guī)則。這一條規(guī)則和 SRP 是一致的趴生,你可能會發(fā)現(xiàn)擁有多個方法的接口實際上會負責多個方面或者功能阀趴。

但是有時只有兩個方法的接口也應(yīng)該分為兩個接口:

在這個例子中,假設(shè)有時候不需要 decode 方法苍匆,并且某一個 codec 在不同的場合有可能當做 endoder 使用刘急,有時可能當做 decoder 使用,那么把 SimpleCodec 拆分成 EncoderDecoder 更合適一些锉桑。有的類可能會同時實現(xiàn)這兩個接口排霉,但是不必讓所有的實現(xiàn)者都去 Override 它們不需要的方法,或者說只需要 Encoder 接口的類注意到它們的 Encoder 實例還實現(xiàn)了 decode民轴。

依賴反轉(zhuǎn)原則(DIP)

依賴于抽象攻柠,而不是具體的實現(xiàn)。

發(fā)現(xiàn)簡單的破壞這一規(guī)則可能比較容易后裸,比如使用 new 關(guān)鍵字(而不是使用依賴注入或者工廠模式)或者對你的集合類型過度熟悉(例如將變量和參數(shù)定義為 ArrayList 而不是 List)瑰钮,作為審查者,你應(yīng)該注意保證代碼作者使用/創(chuàng)建了正確的抽象微驶。

例如浪谴,服務(wù)級別的代碼使用直接和數(shù)據(jù)庫之間的連接來讀寫數(shù)據(jù):

這段代碼依賴于許多具體的實現(xiàn)細節(jié):數(shù)據(jù)庫連接 JDBC,數(shù)據(jù)庫特定的 SQL因苹,數(shù)據(jù)庫的結(jié)構(gòu)等等苟耻。這些代碼應(yīng)該出現(xiàn)在系統(tǒng)的某一個地方,但是不應(yīng)該出現(xiàn)在這里扶檐,也不應(yīng)該出現(xiàn)在不需要了解數(shù)據(jù)庫細節(jié)的方法中凶杖。更好的方法是提取出一個 DAO 或者使用 Repository 模式,然后將 DAO 或者 repository 注入到這個 services款筑。

總結(jié)

這些代碼“味道”可能表示一個或者多個 SOLID 原則被破壞:

  • 很長的 if/else 語句
  • 強制轉(zhuǎn)換到子類型
  • 很多公共方法
  • 實現(xiàn)了拋出 UnsupportedOperationException 的方法

與所有設(shè)計問題一樣智蝠,在遵循這些原則之間找到平衡,并根據(jù)你的團隊的喜好做出調(diào)整奈梳。 但是杈湾,如果在代碼審查中看到復(fù)雜的代碼,你可能會發(fā)現(xiàn)應(yīng)用這些原則之一會找到一個更簡單攘须,更易于理解的解決方案漆撞。

本文譯自: What to look for in a Code Review: SOLID Principles

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叫挟,更是在濱河造成了極大的恐慌艰匙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抹恳,死亡現(xiàn)場離奇詭異员凝,居然都是意外死亡,警方通過查閱死者的電腦和手機奋献,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門健霹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓶蚂,你說我怎么就攤上這事糖埋。” “怎么了窃这?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵瞳别,是天一觀的道長。 經(jīng)常有香客問我杭攻,道長祟敛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任兆解,我火速辦了婚禮馆铁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锅睛。我一直安慰自己埠巨,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布现拒。 她就那樣靜靜地躺著辣垒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪印蔬。 梳的紋絲不亂的頭發(fā)上乍构,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音扛点,去河邊找鬼。 笑死岂丘,一個胖子當著我的面吹牛陵究,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奥帘,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼铜邮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起松蒜,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤扔茅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秸苗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體召娜,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年惊楼,在試婚紗的時候發(fā)現(xiàn)自己被綠了玖瘸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡檀咙,死狀恐怖雅倒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弧可,我是刑警寧澤蔑匣,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站棕诵,受9級特大地震影響裁良,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜年鸳,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一趴久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搔确,春花似錦彼棍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涕蜂,卻和暖如春华匾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背机隙。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工蜘拉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人有鹿。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓旭旭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親葱跋。 傳聞我的和親對象是個殘疾皇子持寄,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 一:java概述:1源梭,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境稍味,java的開發(fā)工...
    ZaneInTheSun閱讀 2,629評論 0 11
  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法废麻,而不是構(gòu)造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法,并非Fa...
    孫小磊閱讀 1,963評論 0 3
  • 轉(zhuǎn)載標注聲明:http://www.uml.org.cn/sjms/201211023.asp 目錄:[設(shè)計模式六...
    Bloo_m閱讀 706評論 0 7
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法模庐,類相關(guān)的語法烛愧,內(nèi)部類的語法,繼承相關(guān)的語法赖欣,異常的語法屑彻,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • 學而10:子禽問于子貢曰:“夫子至于是邦也,必聞其政顶吮。求之與社牲?抑與之與?”子貢曰:“父子溫悴了、良搏恤、恭、儉湃交、讓以得之熟空。...
    驚鴻掠波閱讀 364評論 0 1