S ->Single Responsibility Principle 單一職責原則
應該有且僅有一個原因引起類的變更徒探。
好處:
- 類的復雜性降低,實現(xiàn)什么職責都有清晰明確的定義;
- 可讀性提高圣蝎,復雜性降低娜膘,那當然可讀性提高了;
- 可維護性提高级乍,可讀性提高舌劳,那當然更容易維護了;
- 變更引起的風險降低卡者,變更是必不可少的蒿囤,如果接口的單一職責做得好,一個接口修改只對相應的實現(xiàn)類有影響崇决,對其他的接口無影響材诽,這對系統(tǒng)的擴展性、維護性都有非常大的幫助恒傻。
注意: 單一職責原則提出了一個編寫程序的標準脸侥,用“職責”或“變化原因”來衡量接口或類設計得是否優(yōu)良,但是“職責”和“變化原因”都是不可度量的盈厘,因項目而異睁枕,因環(huán)境而異。單一職責適用于接口、類外遇,同時也適用于方法注簿。
建議:接口一定要做到單一職責,類的設計盡量做到只有一個原因引起變化跳仿。
O ->Open Closed Principle 開閉原則
一個軟件實體如類诡渴、模塊和函數(shù)應該對擴展開放,對修改關(guān)閉菲语。
軟件實體包括
● 項目或軟件產(chǎn)品中按照一定的邏輯規(guī)則劃分的模塊
● 抽象和類
● 方法
好處:
- 減輕重新測試的壓力:新增加的類妄辩,新增加的測試方法,只要保證新增加類是正確的就可以了山上。
- 開閉原則可以提高復用性:縮小邏輯粒度眼耀,直到一個邏輯不可再拆分為止。
- 開閉原則可以提高可維護性
注意: 注意 開閉原則對擴展開放佩憾,對修改關(guān)閉哮伟,并不意味著不做任何修改,低層模塊的變更鸯屿,必然要有高層模塊進行耦合澈吨,否則就是一個孤立無意義的代碼片段。
建議:放棄修改歷史的想法寄摆,一個項目的基本路徑應該是這樣的:項目開發(fā)谅辣、重構(gòu)、測試婶恼、投產(chǎn)桑阶、運維,其中的重構(gòu)可以對原有的設計和代碼進行修改勾邦,運維盡量減少對原有代碼的修改蚣录,保持歷史代碼的純潔性,提高系統(tǒng)的穩(wěn)定性眷篇。
運用:
抽象約束:通過接口或抽象類可以約束一組可能變化的行為萎河,并且能夠?qū)崿F(xiàn)對擴展開放
- 通過接口或抽象類約束擴展,對擴展進行邊界限定蕉饼,不允許出現(xiàn)在接口或抽象類中不存在的public方法
- 參數(shù)類型虐杯、引用對象盡量使用接口或者抽象類,而不是實現(xiàn)類
- 抽象層盡量保持穩(wěn)定昧港,一旦確定即不允許修改
元數(shù)據(jù)(metadata)控制模塊行為擎椰,減少重復開發(fā)
例如:Spring容器,SpringContext配置文件
制定項目章程: 對項目來說创肥,約定優(yōu)于配置
封裝變化:
- 將相同的變化封裝到一個接口或抽象類中达舒;
- 將不同的變化封裝到不同的接口或抽象類中值朋,不應該有兩個不同的變化出現(xiàn)在同一個接口或抽象類中。
L ->Liskov Substitution Principle 里氏替換原則
所有引用基類的地方必須能透明地使用其子類的對象巩搏。
四層含義:
子類必須完全實現(xiàn)父類的方法
注意: 如果子類不能完整地實現(xiàn)父類的方法昨登,或者父類的某些方法在子類中已經(jīng)發(fā)生“畸變”,則建議斷開父子繼承關(guān)系贯底,采用依賴篙骡、聚集、組合等關(guān)系代替繼承丈甸。子類可以有自己的個性
即有子類出現(xiàn)的地方父類未必就可以出現(xiàn)覆蓋或?qū)崿F(xiàn)父類的方法時輸入?yún)?shù)可以被放大
-
覆寫或?qū)崿F(xiàn)父類的方法時輸出結(jié)果可以被縮小
此處復習重寫原則:- 重寫方法不能比被重寫方法限制有更嚴格的訪問級別
- 參數(shù)列表必須與被重寫方法的相同
- 返回類型必須與被重寫方法的返回類型相同,或是子類(子類的返回值也為父類返回值的子類)
- 重寫方法不能拋出新的異衬蛲剩或者比被重寫方法聲明的檢查異常更廣的檢查異常睦擂。但是可以拋出更少,更有限或者不拋出異常
- 不能重寫被標識為final的方法
- 如果一個方法不能被繼承杖玲,則不能重寫它顿仇。如private方法(注意:繼承可以繼承父類private方法,只是沒辦法使用)
繼承的優(yōu)點:
- 代碼共享摆马,減少創(chuàng)建類的工作量臼闻,每個子類都擁有父類的方法和屬性;
- 提高代碼的重用性
- 子類可以形似父類囤采,但又異于父類
- 提高代碼的可擴展性
比如:擴展接口都是通過繼承父類來完成的- 提高產(chǎn)品或項目的開放性
缺點:
- 繼承是侵入性的述呐。只要繼承,就必須擁有父類的所有屬性和方法蕉毯;
- 子類必須擁有父類的屬性和方法乓搬,降低代碼的靈活性。
- 增強了耦合性代虾。
L ->Law of Demeter(Least Knowledge Principle) 迪米特法則(最少知識原則)
一個類應該對自己需要耦合或調(diào)用的類知道得最少
- 只和朋友交流
一個類只和朋友交流进肯,不與陌生類交流,不要出現(xiàn)getA().getB().getC().getD()這種情況(在一種極端的情況下允許出現(xiàn)這種訪問棉磨,即每一個點號后面的返回類型都相同)江掩,類與類之間的關(guān)系是建立在類間的,而不是方法間乘瓤,因此一個方法盡量不引入一個類中不存在的對象环形,當然,JDK API提供的類除外馅扣。 - 朋友間也是有距離的
一個類公開的public屬性或方法越多斟赚,修改時涉及的面也就越大,變更引起的風險擴散也就越大差油。為了保持朋友類間的距離拗军,在設計時需要反復衡量:盡量不要對外公布太多的public方法和非靜態(tài)的public變量任洞,盡量內(nèi)斂,多使用private发侵、package-private交掏、protected等訪問權(quán)限。 - 是自己的就是自己的
如果一個方法放在本類中刃鳄,既不增加類間關(guān)系盅弛,也對本類不產(chǎn)生負面影響,那就放置在本類中 - 謹慎使用Serializable
I ->Interface Segregation Principle 接口隔離原則
接口盡量細化叔锐,同時接口中的方法盡量少挪鹏。
注意:單一職責的審視角度是不相同的,單一職責要求的是類和接口職責單一愉烙,注重的是職責讨盒,這是業(yè)務邏輯上的劃分,而接口隔離原則要求接口的方法盡量少步责。
接口分為兩種:
實例接口(Object Interface)返顺,在Java中聲明一個類,然后用new關(guān)鍵字產(chǎn)生一個實例蔓肯,它是對一個類型的事物的描述遂鹊,這是一種接口。(就是普通類對象)
類接口(Class Interface)蔗包,Java中經(jīng)常使用的interface關(guān)鍵字定義的接口秉扑。
四層含義:
- 接口要盡量小
根據(jù)接口隔離原則拆分接口時,首先必須滿足單一職責原則 - 接口要高內(nèi)聚
要求在接口中盡量少公布public方法 - 定制服務
定制服務就是單獨為一個個體提供優(yōu)良的服務气忠。比如:應對不同的訪問提供不同的接口 - 接口設計是有限度的
靈活的同時也帶來了結(jié)構(gòu)的復雜化邻储,開發(fā)難度增加,可維護性降低
運用:
一個接口只服務于一個子模塊或業(yè)務邏輯
通過業(yè)務邏輯壓縮接口中的public方法
已經(jīng)被污染了的接口旧噪,盡量去修改吨娜,若變更的風險較大,則采用適配器模式進行轉(zhuǎn)化處理
了解環(huán)境淘钟,拒絕盲從宦赠。
D ->Dependence Inversion Principle 依賴倒置原則(面向接口編程)
模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系米母,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的勾扭;
接口或抽象類不依賴于實現(xiàn)類;
實現(xiàn)類依賴接口或抽象類铁瞒。
好處:可以減少類間的耦合性妙色,提高系統(tǒng)的穩(wěn)定性,降低并行開發(fā)引起的風險慧耍,提高代碼的可讀性和可維護性身辨。
三種寫法:
- 構(gòu)造函數(shù)傳遞依賴對象
- Setter方法傳遞依賴對象
- 接口聲明依賴對象
運用:
- 每個類盡量都有接口或抽象類丐谋,或者抽象類和接口兩者都具備
- 變量的表面類型盡量是接口或者是抽象類
- 任何類都不應該從具體類派生(只要不超過兩層的繼承都是可以忍受的,考慮項目維護的成本)
- 盡量不要覆寫基類的方法
- 結(jié)合里氏替換原則使用