成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

超易懂!原來 SOLID 原則要這么理解!

開發(fā) 前端
說到 SOLID 原則,相信有過幾年工作經(jīng)驗(yàn)的朋友都有個大概印象,但就是不知道它具體是什么。甚至有些工作了十幾年的朋友,它們對 SOLID 原則的理解也停留在表面。

 [[381646]]

說到 SOLID 原則,相信有過幾年工作經(jīng)驗(yàn)的朋友都有個大概印象,但就是不知道它具體是什么。甚至有些工作了十幾年的朋友,它們對 SOLID 原則的理解也停留在表面。今天我們就來聊聊 SOLID 原則以及它們之間的關(guān)系。

01 什么是 SOLID 原則

SOLID 原則其實(shí)是用來指導(dǎo)軟件設(shè)計(jì)的,它一共分為五條設(shè)計(jì)原則,分別是:

  • 單一職責(zé)原則(SRP)
  • 開閉原則(OCP)
  • 里氏替換原則(LSP)
  • 接口隔離原則(ISP)
  • 依賴倒置原則(DIP)

單一職責(zé)原則(SRP)

單一職責(zé)原則(Single Responsibility Principle),它的定義是:應(yīng)該有且僅有一個原因引起類的變更。簡單地說:接口職責(zé)應(yīng)該單一,不要承擔(dān)過多的職責(zé)。 用生活中肯德基的例子來舉例:負(fù)責(zé)前臺收銀的服務(wù)員,就不要去餐廳收盤子。負(fù)責(zé)餐廳收盤子的就不要去做漢堡。

單一職責(zé)適用于接口、類,同時也適用于方法。例如我們需要修改用戶密碼,有兩種方式可以實(shí)現(xiàn),一種是用「修改用戶信息接口」實(shí)現(xiàn)修改密碼,一種是新起一個接口來實(shí)現(xiàn)修改密碼功能。在單一職責(zé)原則的指導(dǎo)下,一個方法只承擔(dān)一個職能,所以我們應(yīng)該新起一個接口來實(shí)現(xiàn)修改密碼的功能。

單一職責(zé)原則的重點(diǎn)在于職責(zé)的劃分,很多時候并不是一成不變的,需要根據(jù)實(shí)際情況而定。單一職責(zé)能夠使得類復(fù)雜性降低、類之間職責(zé)清晰、代碼可讀性提高、更加容易維護(hù)。但它的缺點(diǎn)也很明顯,就是對技術(shù)人員要求高,有些時候職責(zé)難以區(qū)分。

我們在設(shè)計(jì)一個類的時候,可以先從粗粒度的類開始設(shè)計(jì),等到業(yè)務(wù)發(fā)展到一定規(guī)模,我們發(fā)現(xiàn)這個粗粒度的類方法和屬性太多,且經(jīng)常修改的時候,我們就可以對這個類進(jìn)行重構(gòu)了,將這個類拆分成粒度更細(xì)的類,這就是所謂的持續(xù)重構(gòu)。

開閉原則(OCP)

開閉原則(Open Closed Principle),它的定義是:一個軟件實(shí)體,如類、模塊和函數(shù)應(yīng)該對擴(kuò)展開放,對修改關(guān)閉。簡單地說:就是當(dāng)別人要修改軟件功能的時候,使得他不能修改我們原有代碼,只能新增代碼實(shí)現(xiàn)軟件功能修改的目的。

這聽著有點(diǎn)玄乎,我來舉個例子吧。

這段代碼模擬的是對于水果剝皮的處理程序。如果是蘋果,那么是一種撥皮方法;如果是香蕉,則是另一種剝皮方法。如果以后還需要處理其他水果,那么就會在后面加上很多 if else 語句,最終會讓整個方法變得又臭又長。如果恰好這個水果中的不同品種有不同的剝皮方法,那么這里面又會有很多層嵌套。

  1. if(type == apple){ 
  2.     //deal with apple  
  3. else if (type == banana){ 
  4.     //deal with banana 
  5. else if (type == ......){ 
  6.     //...... 

可以看得出來,上面這樣的代碼并沒有滿足「對拓展開放,對修改封閉」的原則。每次需要新增一種水果,都可以直接在原來的代碼上進(jìn)行修改。久而久之,整個代碼塊就會變得又臭又長。

如果我們對剝水果皮這件事情做一個抽象,剝蘋果皮是一個具體的實(shí)現(xiàn),剝香蕉皮是一個具體的實(shí)現(xiàn),那么寫出的代碼會是這樣的:

  1. public interface PeelOff { 
  2.     void peelOff(); 
  3.  
  4. public class ApplePeelOff implement PeelOff{ 
  5.     void peelOff(){ 
  6.   //deal with apple 
  7.     } 
  8.  
  9. public class BananaPeelOff implement PeelOff{ 
  10.     void peelOff(){ 
  11.   //deal with banan 
  12.     } 
  13.  
  14. public class PeelOffFactory{ 
  15.     private Map<String, PeelOff> map = new HashMap(); 
  16.  
  17.     private init(){ 
  18.         //init all the Class that implements PeelOff interface  
  19.    } 
  20.  
  21. ..... 
  22.  
  23. public static void main(){ 
  24.     String type = "apple"
  25.     PeelOff peelOff = PeelOffFactory.getPeelOff(type);  //get ApplePeelOff Class Instance. 
  26.     peelOff.pealOff(); 

上面這種實(shí)現(xiàn)方式使得別人無法修改我們的代碼,為什么?

因?yàn)楫?dāng)需要對西瓜剝皮的時候,他會發(fā)現(xiàn)他只能新增一個類實(shí)現(xiàn) PeelOff 接口,而無法在原來的代碼上修改。這樣就實(shí)現(xiàn)了「對拓展開放,對修改封閉」的原則。

里氏替換原則(LSP)

里氏替換原則(LSP)的定義是:所有引用基類的地方必須能透明地使用其子類的對象。簡單地說:所有父類能出現(xiàn)的地方,子類就可以出現(xiàn),并且替換了也不會出現(xiàn)任何錯誤。 例如下面 Parent 類出現(xiàn)的地方,可以替換成 Son 類,其中 Son 是 Parent 的子類。

  1. Parent obj = new Son(); 
  2. 等價(jià)于 
  3. Son son  = new Son(); 

這樣的例子在 Java 語言中是非常常見的,但其核心要點(diǎn)是:替換了也不會出現(xiàn)任何的錯誤。這就要求子類的所有相同方法,都必須遵循父類的約定,否則當(dāng)父類替換為子類時就會出錯。 這樣說可能還是有點(diǎn)抽象,我舉個例子。

  1. public class Parent{ 
  2.     // 定義只能扔出空指針異常 
  3.     public void hello throw NullPointerException(){ 
  4.     } 
  5. public class Son extends Parent{ 
  6.     public void hello throw NullPointerException(){ 
  7.         // 子類實(shí)現(xiàn)時卻扔出所有異常 
  8.         throw Exception; 
  9.     } 

上面的代碼中,父類對于 hello 方法的定義是只能扔出空指針異常,但子類覆蓋父類的方法時,卻扔出了其他異常,違背了父類的約定。那么當(dāng)父類出現(xiàn)的地方,換成了子類,那么必然會出錯。

其實(shí)這個例子舉得不是很好,因?yàn)檫@個在編譯層面可能就有錯誤。但表達(dá)的意思應(yīng)該是到位了。

而這里的父類的約定,不僅僅指的是語法層面上的約定,還包括實(shí)現(xiàn)上的約定。有時候父類會在類注釋、方法注釋里做了相關(guān)約定的說明,當(dāng)你要覆寫父類的方法時,需要弄懂這些約定,否則可能會出現(xiàn)問題。例如子類違背父類聲明要實(shí)現(xiàn)的功能。比如父類某個排序方法是從小到大來排序,你子類的方法竟然寫成了從大到小來排序。

里氏替換原則 LSP 重點(diǎn)強(qiáng)調(diào):對使用者來說,能夠使用父類的地方,一定可以使用其子類,并且預(yù)期結(jié)果是一致的。

接口隔離原則(ISP)

接口隔離原則(Interface Segregation Principle)的定義是:類間的依賴關(guān)系應(yīng)該建立在最小的接口上。簡單地說:接口的內(nèi)容一定要盡可能地小,能有多小就多小。

舉個例子來說,我們經(jīng)常會給別人提供服務(wù),而服務(wù)調(diào)用方可能有很多個。很多時候我們會提供一個統(tǒng)一的接口給不同的調(diào)用方,但有些時候調(diào)用方 A 只使用 1、2、3 這三個方法,其他方法根本不用。調(diào)用方 B 只使用 4、5 兩個方法,其他都不用。接口隔離原則的意思是,你應(yīng)該把 1、2、3 抽離出來作為一個接口,4、5 抽離出來作為一個接口,這樣接口之間就隔離開來了。

那么為什么要這么做呢?我想這是為了隔離變化吧! 想想看,如果我們把 1、2、3、4、5 放在一起,那么當(dāng)我們修改了 A 調(diào)用方才用到 的 1 方法,此時雖然 B 調(diào)用方根本沒用到 1 方法,但是調(diào)用方 B 也會有發(fā)生問題的風(fēng)險(xiǎn)。而如果我們把 1、2、3 和 4、5 隔離成兩個接口了,我修改 1 方法,絕對不會影響到 4、5 方法。

除了改動導(dǎo)致的變化風(fēng)險(xiǎn)之外,其實(shí)還會有其他問題,例如:調(diào)用方 A 抱怨,為什么我只用 1、2、3 方法,你還要寫上 4、5 方法,增加我的理解成本。調(diào)用方 B 同樣會有這樣的困惑。

在軟件設(shè)計(jì)中,ISP 提倡不要將一個大而全的接口扔給使用者,而是將每個使用者關(guān)注的接口進(jìn)行隔離。

依賴倒置原則(DIP)

依賴倒置原則(Dependence Inversion Principle)的定義是:高層模塊不應(yīng)該依賴底層模塊,兩者都應(yīng)該依賴其抽象。抽象不應(yīng)該依賴細(xì)節(jié),即接口或抽象類不依賴于實(shí)現(xiàn)類。細(xì)節(jié)應(yīng)該依賴抽象,即實(shí)現(xiàn)類不應(yīng)該依賴于接口或抽象類。簡單地說,就是說我們應(yīng)該面向接口編程。通過抽象成接口,使各個類的實(shí)現(xiàn)彼此獨(dú)立,實(shí)現(xiàn)類之間的松耦合。

如果我們每個人都能通過接口編程,那么我們只需要約定好接口定義,我們就可以很好地合作了。軟件設(shè)計(jì)的 DIP 提倡使用者依賴一個抽象的服務(wù)接口,而不是去依賴一個具體的服務(wù)執(zhí)行者,從依賴具體實(shí)現(xiàn)轉(zhuǎn)向到依賴抽象接口,倒置過來。

02 SOLID 原則的本質(zhì)

我們總算把 SOLID 原則中的五個原則說完了。但說了這么一通,好像是懂了,但是好像什么都沒記住。 那么我們就來盤一盤他們之間的關(guān)系。ThoughtWorks 上有一篇文章說得挺不錯,文中說:

  • 單一職責(zé)是所有設(shè)計(jì)原則的基礎(chǔ),開閉原則是設(shè)計(jì)的終極目標(biāo)。
  • 里氏替換原則強(qiáng)調(diào)的是子類替換父類后程序運(yùn)行時的正確性,它用來幫助實(shí)現(xiàn)開閉原則。
  • 而接口隔離原則用來幫助實(shí)現(xiàn)里氏替換原則,同時它也體現(xiàn)了單一職責(zé)。
  • 依賴倒置原則是過程式編程與面向?qū)ο缶幊痰姆炙畮X,同時它也被用來指導(dǎo)接口隔離原則。

圖片 l 來自 ThoughtWorks

簡單地說:依賴倒置原則告訴我們要面向接口編程。當(dāng)我們面向接口編程之后,接口隔離原則和單一職責(zé)原則又告訴我們要注意職責(zé)的劃分,不要什么東西都塞在一起。

當(dāng)我們職責(zé)捋得差不多的時候,里氏替換原則告訴我們在使用繼承的時候,要注意遵守父類的約定。而上面說的這四個原則,它們的最終目標(biāo)都是為了實(shí)現(xiàn)開閉原則。

參考資料

  • 寫了這么多年代碼,你真的了解 SOLID 嗎?- 知乎
  • 如何理解 SOLID 原則?- ThoughtWorks 洞見
  • 重構(gòu)的七宗罪 - ThoughtWorks 洞見

本文轉(zhuǎn)載自微信公眾號「陳樹義」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系陳樹義公眾號。

 

責(zé)任編輯:武曉燕 來源: 陳樹義
相關(guān)推薦

2022-03-24 09:44:54

TypeScriptSOLID

2022-09-27 09:21:34

SOLID開閉原則Go

2017-10-24 15:28:27

PHP代碼簡潔SOLID原則

2021-04-19 05:42:51

Mmap文件系統(tǒng)

2010-09-13 13:06:42

2022-07-15 09:01:15

React對象編程

2023-11-01 14:49:07

2010-08-27 10:26:16

2024-09-30 11:51:07

2022-12-06 17:30:04

2019-04-30 14:59:27

Wi-FiWi-Fi 6Wi-Fi 5

2023-05-07 23:22:24

golang

2020-05-14 09:15:52

設(shè)計(jì)模式SOLID 原則JS

2021-08-29 18:13:03

緩存失效數(shù)據(jù)

2014-10-08 15:00:50

SUSE操作系統(tǒng)云計(jì)算

2019-03-15 10:55:12

通信系統(tǒng)手機(jī)

2012-05-08 10:14:45

設(shè)計(jì)原則

2023-09-22 08:00:00

分布式鎖Redis

2020-09-24 06:44:54

HTTPS網(wǎng)站 HTTP

2022-10-21 08:17:13

MongoDB查詢Document
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩精品成人在线 | 国产亚洲精品久久久优势 | 国产精品福利在线观看 | 一区二区三区成人 | 国产精品福利在线观看 | 无码国模国产在线观看 | 久久青 | 欧美激情在线精品一区二区三区 | 一本大道久久a久久精二百 国产成人免费在线 | 欧美久久久久久久久中文字幕 | 亚洲精品亚洲人成人网 | 碰碰视频| 日韩欧美精品 | 在线观看免费av片 | 亚洲一二三在线观看 | 精品久久久久久久久亚洲 | 粉嫩在线 | 欧美a免费 | a在线观看 | 精品亚洲一区二区三区 | 国产馆 | 日本一区精品 | 99久热在线精品视频观看 | www.99热这里只有精品 | 成人久久18免费网站 | 免费激情 | 亚洲国产免费 | 日韩成人av在线 | 欧美日韩在线一区二区 | 午夜电影在线播放 | 欧美综合国产精品久久丁香 | 日韩一三区 | 成人网av | 国产精品精品视频一区二区三区 | 日本精品视频在线观看 | 日韩欧美中文在线 | 日韩免费一级 | 成人福利网站 | 久久新视频 | 国产一极毛片 | 国产精品久久久久久久久久免费看 |