SOLID 設計原則包含以下 5 種原則:
- 單一職責原則(Single Responsibility Principle, SRP)
- 開閉原則(Open Closed Principle, OCP)
- 里式替換原則(Liskov Substitution Principle, LSP)
- 介面隔離原則(Interface Segregation Principle, ISP)
- 依賴反轉原則(Dependency Inversion Principle, DIP)
單一職責原則
理解
單一職責原則的描述是,一個類或者模塊只負責完成一個職責(或功能),當然,單一職責原則不止是可以針對于模塊或類,對于很多粒度都有效果,如函式、類、介面、模塊等等,模塊通常由多個類組成,
職責可以指模塊變化的原因,從這個角度理解,單一職責原則表示不要存在超過一個導致模塊變更的原因,
需要注意的是,不同的應用場景、不同階段的需求背景、不同的業務層面,對同一個類的職責是否單一,可能會有不同的判定結果,
優點
遵循單一職責原則,將會有以下的優點:
- 提高代碼的可維護性:職責越少,復雜度越低,可讀性更好,可維護性就更高
- 降低代碼變更的風險:職責越多,代碼變更的可能性就越高,變更帶來的風險也就越大
最佳實踐
在實際開發中,出現以下現象有可能違反了單一職責原則:
- 模塊的變數、屬性或代碼行數過多
- 模塊的內部對外部依賴過多
- 模塊的私有方法過多
- 難以給模塊取一個合理的名稱
- 模塊的大部分操作只針對幾個屬性
如出現上述情況,則需要判斷是否對代碼做職責分離,以遵循單一職責原則,最終應以提高內聚、降低耦合、保證代碼的可維護性為主,
開閉原則
理解
開閉原則的描述是,軟體物體(模塊、類、方法等)應該“對擴展開放、對修改關閉”,
詳細的解釋就是,添加一個新的功能時,在已有代碼基礎上擴展代碼(新增模塊、類、方法等),而非修改已有代碼(修改模塊、類、方法等),更寬松的理解是以最小的修改代碼的代價來完成新功能的開發,
優點
遵循開閉原則,將會有以下的優點:
- 減少測驗范圍:修改的代碼范圍越小,涉及的測驗范圍越小,未改動的測驗代碼仍能正常運行
- 降低維護成本:軟體規模越大、壽命越長,則軟體的維護成本越高
最佳實踐
若要做到“對擴展開發、對修改關閉”,有以下幾點需要注意:
- 時刻具備擴展意識、抽象意識、封裝意識,多花時間設計代碼結構,事先留好擴展點
- 大部分經典設計模式都是為了解決代碼的擴展性問題而總結出來的,開閉原則是它們一個重要的評價依據
里式替換原則
理解
里式替換原則的描述是,子類物件能夠替換程式中父類物件出現的任何地方,并且保證原來程式的邏輯行為不變及正確性不被破壞,
從代碼實作上看,面向物件的多型和里式替換原則有點類似,但是它們的關注點不一樣:里式替換原則是用來指導繼承關系中子類該如何設計,子類的設計要保證在替換父類的時候,不改變原有程式的邏輯以及不破壞原有程式的正確性,
優點
遵循里式替換原則,將會有以下的優點:
- 實作有意義的繼承:保證了父類的復用性,也降低了系統出錯誤的故障,防止誤操作,同時也不會破壞繼承的機制
- 增強程式的健壯性:不同的子類可以完成不同的業務邏輯,即使增加子類也能保持非常好的兼容性
最佳實踐
通常,需要注意以下違反里式替換原則的代碼:
- 子類違背父類宣告要實作的功能,如將加法改成減法
- 子類違背父類對輸入、輸出、例外的約定,如同一情況拋出的例外不同等
- 子類違背父類注釋中所羅列的任何特殊宣告
介面隔離原則
理解
介面隔離原則的描述是,介面的呼叫者或使用者不應該被強迫依賴它不需要的介面,
通過對介面的理解不同,介面隔離原則有以下三種理解:
1、如果把“介面”理解成一組介面集合,可以是某個微服務的介面,也可以是某個類別庫的介面等,如果存在部分介面只被部分呼叫者使用,就需要將這部分介面隔離出來,單獨給這部分呼叫者使用,而不強迫其他呼叫者也依賴其他不會用到的介面,
2、如果把“介面”理解成單個 API 介面或函式,部分呼叫者只需要其中的部分功能,則需要將這個函式拆分成更細粒度的多個函式,讓呼叫者只依賴它需要的那個細粒度函式,
3、如果把“介面”理解成 OOP 中的介面,也可以理解成為面向物件編程語言中的介面語法,那介面的設計要盡量單一,不要讓介面的實作類和呼叫者依賴不需要的介面函式,
介面隔離原則和單一職責原則有點類似,但介面隔離原則更側重于介面的設計,通常是通過呼叫者如何使用介面來定義這個介面的設計是否足夠職責單一,
優點
遵循介面隔離原則,將會有以下的優點:
- 高內聚,低耦合:拆分成更小粒度的介面,減少對外的互動,預防外來的變更,提高系統的靈活性和可維護性
- 可讀性高,易于維護:合理的介面拆分粒度能保證系統的穩定性,減少專案工程的代碼冗余
最佳實踐
采用介面隔離原則對介面進行約束時,要注意以下幾點:
- 介面盡量小,但是要有限度,定義過小,則會造成介面數量過多,使設計復雜化;定義多大,靈活性降低
- 每個專案和產品都有選定的環境因素,環境不同,介面拆分的標準就不同,深入了解業務邏輯
依賴反轉原則
理解
依賴反轉原則也被叫作依賴倒置原則,其含義是:高層模塊不要依賴底層模塊,高層模塊和底層模塊應該通過抽象來互相依賴;抽象不要依賴具體實作細節,具體實作細節依賴抽象,
Tomcat 是運行 Java Web 應用程式的容器,撰寫的 Web 應用程式代碼只需要部署在 Tomcat 容器中下,便可被 Tomcat 容器呼叫執行,在這里,Tomcat 容器就是高層模塊,Web 應用程式就是底層模塊,Tomcat 容器和 Web 應用程式沒有直接的依賴關系,而是通過 Servlet 規范實作互相依賴,而 Servlet 規范也不會依賴具體的實作細節,而是 Tomcat 和 Web 應用程式依賴 Servlet 規范,
控制反轉
控制反轉(Inversion Of Control, IoC)指的是將程式員自己對程式執行流程的控制反轉成通過框架控制,控制反轉并不是一種具體的設計技巧,而是一種籠統的設計思想,一般用來指導框架層面的設計,
實作控制反轉主要有兩種方式:依賴注入和依賴查找,兩者的區別在于,前者是被動的接收物件,在類 A 的實體創建程序中即創建了依賴的 B 物件,通過型別或名稱來判斷將不同的物件注入到不同的屬性中,而后者是主動索取相應型別的物件,獲得依賴物件的時間也可以在代碼中自由控制,
依賴注入
依賴注入(Dependency Injection, DI)是一種具體的編碼技巧,
其詳細概括就是:不通過 new 的方式在類的內部創建依賴物件,而是將依賴的類物件在外部創建好之后,通過建構式、函式引數等方式傳遞(或注入)給類使用,
一個簡單的依賴注入代碼例子如下:
package cn.fatedeity.designpattern.philosophy;
/**
* 依賴注入案例
*/
public class DependencyInjectionCase {
private MessageSender messageSender;
public DependencyInjectionCase(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void sendMessage(String phone, String message) {
this.messageSender.send(phone, message);
}
public static void main(String[] args) {
MessageSender smsSender = new SmsSender();
DependencyInjectionCase dependencyInjectionCase0 = new DependencyInjectionCase(smsSender);
// SmsSender sms send sms message
dependencyInjectionCase0.sendMessage("sms", "sms message");
MessageSender inboxSender = new InboxSender();
DependencyInjectionCase dependencyInjectionCase1 = new DependencyInjectionCase(smsSender);
// SmsSender inbox send inbox message
dependencyInjectionCase1.sendMessage("inbox", "inbox message");
}
}
class InboxSender implements MessageSender {
@Override
public void send(String phone, String message) {
System.out.println("InboxSender " + phone + " send "+ message);
}
}
class SmsSender implements MessageSender {
@Override
public void send(String phone, String message) {
System.out.println("SmsSender " + phone + " send "+ message);
}
}
interface MessageSender {
void send(String phone, String message);
}
優點
遵循依賴反轉原則,將會有以下的優點:
- 查詢依賴和應用代碼分離,大量降低工廠類和單例類的數量,代碼層次更加清晰
- 沒有侵入性,無須依賴容器的 API,也無須實作一些特殊介面
最佳實踐
通過依賴注入提供的擴展點,簡單配置一下所有需要的類及其類之間依賴關系,就可以實作由框架來自動創建物件、管理物件的生命周期、依賴注入等功能,
現成的依賴注入創建有很多,比如 Google Guide、Java Spring、Pico Container、Butterfly Container 等,
首發于翔仔的個人博客,點擊查看更多,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/502263.html
標籤:設計模式
上一篇:HSF轉dubbo
下一篇:HSF轉dubbo
