我對SOLID的理解

超前的設計或者過分的設計都不是良好的設計,不少時候咱們等到代碼在第一次變化的時候能夠及時做出反應就夠了java

單一責任原則(The Single Responsibility Principle )

根據實際狀況,拿捏需求的拆分力度,根據拆分的塊,來設計對應的類

單一責任原則:咱們設計一個類的時候,應該儘可能把類的職責單一化;那麼咱們拿到需求的時候,應該對需求進行分析,再拆分職責,再設計對應的類。在實際工做中吧,其實大部分的程序猿都知道這個道理,主要的阻力是開發時間(偷懶),爲了方便處理就不搞太多類了;仍是有個緣由,就是若是拆分力度大,拆分的太細,那麼可能會出現一個簡單的需求,你寫了好幾個類,這樣也不是可取的,這種有點過分設計了,沒有必要。編程

舉個例子吧,我是作iOS的,就說說界面相關的需求吧,好比說如今產品的需求是作一個word功能的屬性面板,裏面有幾個模塊:選擇字體,設置對齊方式,設置字體顏色,每一個模塊都是列表(tableView),那麼在開發前,就應該拆分好,好比說屬性面板(容器類),三個子模塊(對應三個類),這樣來開發,這就是單一責任的應用了架構

再舉個例子,好比這時候要設計一個工廠類,工廠類須要生產A,B產品,還有一個原料的預加工,如今的需求是原料的預加工,A和B都是同樣的,也就是說A和B能夠共用這個方法,那麼這三個功能就都堆在工廠類裏面了。這樣是違背了單一責任原則了,可是若是需求確實這邊簡單,比較小需求,那麼這樣來開發我以爲也沒有問題,畢竟對於大部分懟業務的程序猿來講,又快又穩的出貨纔是王道。框架

若是第二期需求來了,要求改動A產品的預加工方式,那麼這時候,A和B就不能夠公用一個預加工方法了,那麼這個時候,就是要及時做出從新設計的考慮了,並且這時候的考慮能夠多考慮一下將來可能的改動。測試

說回剛來產品要求改A產品的預加工需求,若是咱們改了工廠類的預加工方法,那麼B產品就受影響了。這個就說明了單一責任原則的重要性了,可能下降之後版本迭代中,改動的影響面。對於這個例子,可能一些同窗以爲這個很簡單就知道我改動預加工方法會影響到B產品,問題是,在比較大項目,複雜的項目中,有時候改動了一個地方,影響到另外一個地方是很難發現的,測試階段發現還好,有時候可能不是很明顯,也不是嚴重的影響,有可能上線了很久才偶然間發現字體

除了類須要遵循單一職責原則,方法也一樣須要,通常方法內的代碼不能太多.net

開閉原則(The Open Closed Principle)

用抽象構建框架,用實現擴展細節

開閉原則:就是寫的代碼即要有開放性,也要有封閉性,好比如今寫一個加法需求,若是一開始就寫一個加法類,那麼後期擴展,有減法,乘法,除法等,那麼是否是繼續建立新的類,那麼這些加減乘除是否是應該會存在共用的東西,那麼就能夠抽成一個計算類,這個計算類能夠作一些共用的約束,好比計算類能夠有formula公式方法,result計算結果的方法,而後加減乘除繼承於計算類,重寫對應的方法便可。架構設計

那麼這樣的操做,就是對計算類封閉,可是計算類又對外開放,好比繼承他,去實現一些細節問題設計

因此開閉原則說的就是這個意思,用抽象構建框架,用實現擴展細節,好比抽象類(計算類),實現細節由加減乘除子類去作。代理

須要說明的是,對修改關閉不是說軟件設計不能作修改,只是儘可能不要作沒必要要的修改。怎麼才能作到呢?那就是有相應的擴展性。

其實,軟件有相應的擴展性是好處,可是不能說每一個地方都有擴展。反而形成了代碼的臃腫。因此這裏的擴展與修改關閉是有限制的。這個結合實際的工做開發,若是咱們遇到的需求,都考慮弄個抽象類,都本身考慮了之後的一堆擴展,不是說這個考慮很差,只是在開發上浪費了時間,有可能你的架構,在將來很長時間都沒有用上,那麼這就形同臃腫的架構設計,因此實際開發,仍是要按照實際狀況去處理,不要爲了達到開閉原則寫開閉原則。

還有抽象層儘可能保持穩定,儘可能不修改,由於咱們在開發中,修改老舊代碼,評估最多的是影響面,若是動到了抽象層,意味着影響面很大

里氏替換原則(Liskov Substitution Principle)

規範子類的書寫規則,實現父類抽象方法,不能覆蓋父類的具體方法,以此達到父類的方法不被覆蓋和父類能夠出現的地方,子類就能出現(意思就是好比一個方法的參數是傳父類類型,那麼這時候傳子類進去,也得是沒有問題的)

咱們設計基類的時候,應該儘可能作到基類是抽象的,儘可能抽象,若是一個基類的功可以完善,那麼這個應該定義爲具體類,而不是基類,由於越完善越具體的類,之後子類繼承他,子類的擴展性就越差。這就違背了開閉原則。

至於里氏替換原則,說的就是規範一些子類寫法的規則,好比

  • 子類能夠實現父類的抽象方法,可是不能覆蓋父類的具體方法
  • 子類能夠增長本身特有的方法
  • 當子類覆蓋或實現父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬鬆。
  • 當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。

第三和四點不太理解,這有一個詳細的問題,可是我沒看懂(https://blog.csdn.net/qq_3496...

說簡單點就是開閉原則就是父類儘可能抽象,子類擴展,里氏替換原則就是子類實現的細節怎麼來寫,怎麼規範,還有繼承必須確保父類所擁有的性質在子類中仍然成立。

接口隔離原則(Interface Segregation Principle)

接口儘可能細化,不要臃腫,這裏接口的意思就是oc的代理,java的interface

好比如今接口1有5個方法,類A依賴接口1的1-3個方法,類B依賴接口1的3-5個方法;那麼類A依賴接口1就必須實現這5個方法,可是四、5方法對於類A來講是徹底沒有必要實現的,因此這樣的接口1設計就是臃腫的,因此咱們應該細化他,變成兩個接口,對應類A和B

在oc中代理方法有可選的,那麼彷佛就沒有這個問題了,這麼看也確實沒有,可是@protocol設置@optional的意思是,能夠實現,也能夠不實現,是非必須的意思。接口隔離原則就是徹底沒必要要實現的,這種狀況就須要考慮拆分,細化接口

依賴倒置原則(Dependency Inversion Principle)

面向抽象(接口)編程

接口,抽象,意思就是定義一種規範,協議,本身不實現具體的代碼,只是指明瞭大方向的意思,好比一個公司的老闆就是接口,就是抽象的,由於他不用作細節的東西,可是他指定的方向,規範

細節就是具體的實現

好比在iOS中,協議就是接口,抽象類的抽象方法也是接口,咱們常說要面向接口編程,而不是面向實現編程,由於接口是文檔的,細節的實現是多變的。咱們的編程是追求穩定維護程序的,因此咱們要面向接口編程

舉個例子

初級程序猿類primary
方法:個人工資是1萬

薪酬管理類
方法:claculate:(primary *)pri

那麼薪酬管理類能夠計算出初級程序猿的工資了,可是有個問題,若是要計算中級程序猿的話,那薪酬管理類不就得再添加方法,由於claculate:(primary *)pri方法的入參是初級程序猿類,那這樣不行,之後愈來愈多崗位不就得總去修改薪酬管理類。

因此這時候,咱們要面向接口編程

定義一個協議

@protocol EmployeeDelegate <NSObject>
- (void)calculateSalary; 
@end

薪酬管理類

- (void)claculate:(id<EmployeeDelegate>)pri;

這樣每一個崗位都實現代理方法,而後薪酬管理類的入參是實現了對應代理方法的類,這樣就不用新增崗位,就去改管理類的代碼了,這就是面向接口編程的一個例子了

總結

單一責任原則是最基本的編程要求,通常咱們主要一個類一個責任,一個方法一個責任這樣寫編寫代碼。關於代碼整潔的話,個人理解就是作到抽取代碼,方法內容簡潔,對應的方法內作對應的事,這樣能夠方便之後的查找,維護。

開閉原則就是說要用抽象搭建框架,實現擴展細節,細節交給具體類或者子類來處理和擴展

里氏替換原則就是規範子類的規範;

接口隔離原則,接口(這裏的接口指oc的協議)細化,不要臃腫;

依賴倒置原則,就是面向接口編程

我對SOLID之間關係的理解:單一責任原則是最基本的編程原則;開閉原則是整個程序架構的最終目標,里氏替換原則、接口隔離原則,依賴倒置原則都是爲了實現開閉原則

相關文章
相關標籤/搜索