I walk very slowly, but I never walk backwards
設計模式原則 - 依賴倒轉原則
寂然
大家好,我是寂然~,本節課呢,我來給大家介紹設計模式原則之依賴倒轉原則,話不多說,我們直接進入正題,老規矩,首先帶大家了解一下依賴倒轉原則的官方定義,并作一個解釋,然後我們通過案例代碼來具體分析
官方定義
依賴倒轉原則,又稱依賴倒置原則(Dependence Inversion Principle),又稱DIP原則,官方定義為:
High level modules should not depend upon low level modules. Both should depend upon abstractions.
(上層子產品不應該依賴底層子產品,它們都應該依賴于抽象)
Abstractions should not depend upon details. Details should depend upon abstractions.
(抽象不應該依賴于細節,細節應該依賴于抽象)
基本介紹
依賴倒轉原則是基于這樣的設計理念:相對于細節的多變性,抽象的東西要穩定的多,以抽象為基礎搭建的架構要比以細節為基礎的架構穩定的多,在Java中,抽象指的是接口或抽象類,細節指具體的實作類,即要求程式要依賴于抽象接口,不要依賴于具體實作
使用接口或者抽象類的目的是制定好規範,而不涉及任何具體的操作,把展現細節的任務交給他們的實作類去完成
換句話說,接口或者抽象類的價值就在于設計
案例示範 - 釘釘消息
OK,那我們假設有這樣一個場景,有一個從業人員,每天要接收釘釘工作消息,簡易代碼如下圖所示
//從業人員
class Worker {
public void getMessage(Dingding dingding){
dingding.sendMessage();
}
}
//釘釘類
class Dingding{
public void sendMessage(){
System.out.println("釘釘上老闆喊你加班呢");
}
}
//測試代碼
public class InversionDemo{
public static void main(String[] args) {
new Worker().getMessage(new Dingding());
}
}
案例分析
OK,可以看到上面的代碼,對案例場景進行了簡易的實作,那我們就對上面的代碼進行分析
現在是擷取釘釘消息,如果我們擷取的對象是微信,短信等,那根據上面的實作,我們需要新增類,同時Worker類也要增加相應的接收方法,這樣顯然維護性很差的同時,頻繁修改代碼也會帶來意想不到的風險
那我們就想到了上面依賴倒轉原則的定義,既然接口或者抽象類的價值就在于設計,我們可以引入一個接口來指定規範,表示資訊的接收者,因為微信,釘釘都屬于消息接收的途徑,那就可以讓他們實作該接口,來完成具體的細節,然後Worker與該接口發生依賴,使用依賴倒轉的思想,完成代碼改造
解決方案
OK,那根據上面的思路,我們對案例代碼進行改造,改造後的代碼示例如下:
//定義接口,指定接收消息的規範
interface IMessage{
public void sendMassage();
}
//釘釘消息
class Dingding implements IMessage{
@Override
public void sendMassage() {
System.out.println("釘釘上老闆喊你開會啦");
}
}
//微信消息
class Weixin implements IMessage{
@Override
public void sendMassage() {
System.out.println("微信上老闆喊你加班啦");
}
}
//從業人員
class Worker {
//這裡是我們對于接口的依賴
public void getMessage(IMessage message){
message.sendMassage();
}
}
//簡易測試代碼
public class Inversion01Demo{
public static void main(String[] args) {
new Worker().getMessage(new Dingding());
new Worker().getMessage(new Weixin());
}
}
案例總結
可以看到,通過上面改造過的代碼,我們定義了接口作為模闆,讓各種消息接收的途徑去實作,這樣的話如果業務要求還需要接收短信的消息,添加短信類實作接口即可,從業人員端不需要進行變動和維護,其實依賴倒置原則的本質上就是通過抽象(抽象類或接口)使各個類或子產品實作彼此獨立,不互相影響,實作子產品間的松耦合
一句話:依賴倒置原則的核心就是面向抽象(抽象類或者接口)程式設計,大家要明白,以抽象為基準搭建起來的架構比以細節為基準搭建的架構要穩定的多,是以,在拿到需求之後,要先頂層再細節的方式來進行代碼設計
依賴關系傳遞方式
當我們進行依賴倒轉的時候,一定要進行依賴關系的傳遞,接着,我們簡單聊聊依賴關系的三種傳遞方式
一、通過接口傳遞
使用接口傳遞,示例代碼如下
//通過接口方式傳遞
interface IMessage{
public void sendMassage(Produce produce); //抽象方法,接收接口
}
interface Produce{
void produceMessage();
}
//從業人員
class Worker implements IMessage{
@Override
public void sendMassage(Produce produce) {
produce.produceMessage();
}
}
可以看到,Worker實作了接口 IMessage,實作了裡面的方法,該方法參數接收了 Produce 接口類型,這就是一個典型的使用接口傳遞的案例,抽象方法sendMassage() 裡面傳的是一個接口
二、通過構造方法傳遞
使用構造方法傳遞,示例代碼如下
//通過構造器方式傳遞
interface IMessage{
public void sendMassage(); //這裡沒有接收接口
}
interface Produce{
void produceMessage();
}
class Worker implements IMessage{
public Produce produce; //屬性為Produce類型
public Worker(Produce produce) { //構造器來傳遞
this.produce = produce;
}
@Override
public void sendMassage() {
this.produce.produceMessage();
}
}
可以看到,這種方式,将Produce置為 Worker類的屬性,值通過構造器來傳遞,賦給 this.produce ,然後在sendMassage()方法裡通過 this.produce 來調用目标方法
三、通過setter()方法傳遞
使用setter()方法傳遞,執行個體代碼如下
//通過setter方式傳遞
interface IMessage{
public void sendMassage();
}
interface Produce{
void produceMessage();
}
class Worker implements IMessage{
public Produce produce; //屬性為Produce類型
public void setProduce(Produce produce) {
this.produce = produce;
}
@Override
public void sendMassage() {
this.produce.produceMessage();
}
}
可以看到,這種方式,将Produce置為 Worker類的屬性,值通過setter()方法來傳遞,賦給 this.produce ,然後在sendMassage()方法裡通過 this.produce 來調用目标方法produceMessage()
注意事項&細節
- 低層子產品盡量都要有抽象類或接口,或者兩者都有,程式穩定性更好
- 變量的聲明類型盡量是抽象類或者接口,這樣我們的變量引用和實際對象間,就存在一個緩沖層,利于程式擴充和優化
- 繼承時遵循裡式替換原則(下章内容來詳細介紹)
下節預告
OK,下一節,我們正式進入設計模式原則之裡式替換原則的學習,我會為大家用多個案例分析,來解讀設計模式原則之裡式替換原則,以及它的注意事項和細節,最後,希望大家在學習的過程中,能夠感覺到設計模式的有趣之處,高效而愉快的學習,那我們下期見~