軟件架構設計原則之依賴倒置原則


依賴倒置原則(Dependence Inversion Principle,DIP)是指設計代碼結構時,高層模塊不應該依賴低層模塊,二者都應該依賴其抽象。抽象不應該依賴細節,細節應該依賴抽象。通過依賴倒置,可以減少類與類之間的耦合性,提高系統的穩定性,提高代碼的可讀性和可維護性,並且能夠降低修改程序所造成的風險。接下來看一個案例,還是以Course(課程)為例,先來創建一個類Tom:

public class Tom {
    public void studyJavaCourse(){
        System.out.println("Tom在學習Java的課程");
    }

    public void studyPythonCourse(){
        System.out.println("Tom在學習Python的課程");
    }
}

來調用一下:

public static void main(String[] args) {
    Tom tom = new Tom();
    tom.studyJavaCourse();
    tom.studyPythonCourse();
}

Tom熱愛學習,目前正在學習Java課程和Python課程。大家都知道,學習也是會上癮的。隨着學習興趣的“暴漲”,現在Tom還想學習AI(人工智能)的課程。這時候,因為業務擴展,要從低層到高層(調用層)依次修改代碼。在Tom類中增加studyAICourse()方法,在高層也要追加調用。如此一來,系統發布以后,實際上是非常不穩定的,在修改代碼的同時也會帶來意想不到的風險。接下來我們優化代碼,創建一個課程的抽象ICourse接口:

public interface ICourse {
    void study();
}

然后編寫JavaCourse類:

public class JavaCourse implements ICourse {
    @Override
    public void study() {
        System.out.println("Tom在學習Java課程");
    }
}

再實現PythonCourse類:

public class PythonCourse implements ICourse {
    @Override
    public void study() {
        System.out.println("Tom在學習Python課程");
    }
}

修改Tom類:

public class Tom {
    public void study(ICourse course){
        course.study();
    }
}

來看調用代碼:

public static void main(String[] args) {
    Tom tom = new Tom();
    tom.study(new JavaCourse());
    tom.study(new PythonCourse());
}

這時候再看來代碼,Tom的興趣無論怎么暴漲,對於新的課程,只需要新建一個類,通過傳參的方式告訴Tom,而不需要修改底層代碼。實際上這是一種大家非常熟悉的方式,叫依賴注入。注入的方式還有構造器方式和Setter方式。我們來看構造器注入方式:

public class Tom {

    private ICourse course;

    public Tom(ICourse course){
        this.course = course;
    }

    public void study(){
        course.study();
    }
}

看調用代碼:

public static void main(String[] args) {
    Tom tom = new Tom(new JavaCourse());
    tom.study();
}

根據構造器方式注入,在調用時,每次都要創建實例。如果Tom是全局單例,則我們就只能選擇用Setter方式來注入,繼續修改Tom類的代碼:

public class Tom {
    private ICourse course;
    public void setCourse(ICourse course) {
        this.course = course;
    }
    public void study(){
        course.study();
    }
}

看調用代碼:

public static void main(String[] args) {
    Tom tom = new Tom();
    tom.setCourse(new JavaCourse());
    tom.study();

    tom.setCourse(new PythonCourse());
    tom.study();
}

現在我們再來看最終的類圖,如下圖所示。

大家要切記:以抽象為基准比以細節為基准搭建起來的架構要穩定得多,因此在拿到需求之后,要面向接口編程,先頂層再細節地設計代碼結構。

關注微信公眾號『 Tom彈架構 』回復“設計模式”可獲取完整源碼。

【推薦】Tom彈架構:30個設計模式真實案例(附源碼),挑戰年薪60W不是夢

本文為“Tom彈架構”原創,轉載請注明出處。技術在於分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力。關注微信公眾號『 Tom彈架構 』可獲取更多技術干貨!

其他設計原則

Tom彈架構:開閉原則(Open-Closed Principle,OCP)

Tom彈架構:單一職責原則(Simple Responsibility Pinciple,SRP)

Tom彈架構:接口隔離原則(Interface Segregation Principle, ISP)

Tom彈架構:迪米特原則(Law of Demeter LoD)

Tom彈架構:里氏替換原則(Liskov Substitution Principle,LSP)

Tom彈架構:合成復用原則(Composite/Aggregate Reuse Principle,CARP)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM