解耦技巧——依賴注入!

在以前的一篇博客 Java Builder 模式,你搞懂了麼? 中,咱們提到了在 oop 編碼設計中 只要能拿到類的實例,即對象,就能命令對象作一系列事情了。在 java/android 程序中,每一個功能模塊都由 n 個 類所組成,而每一個類都封裝了各自的功能,咱們實例化每一個類的實例,分別命令他們去完成指定的功能,可是,程序設計中,類之間每每不是單獨去完成任務的,他們存在相互依賴的關係,就好比 A 類依賴 B 類,B 類又依賴 C 類,A 類 又同時依賴 C 類等等。這樣構成了一個錯綜複雜的關係網。先來個簡單代碼直觀的感覺~java

仍是以 製造 car 爲例子。CarCreateTechnology 製造汽車的技術封裝接口。android

public interface CarCreateTechnology {
    String createCar();
}

CarAutoCreate 製造汽車的技術封裝接口的實現類,具體邏輯由他實現。程序員

public class  CarAutoCreate implements CarCreateTechnology{
    @Override
    public String createCar() {
        return "自動生產的 car ~";
    }
}

CarFactory 汽車工廠類:segmentfault

public class CarFactory {
    private CarCreateTechnology mCreateTechnology;

    public CarFactory() {
        mCreateTechnology = new CarAutoCreate();
    }
    public String createCar(){
        return mCreateTechnology.createCar();
    }
}

最終 實例化 CarFactory 調用 createCar() 方法生產出 car
String car = new CarFactory().createCar();哈哈,這樣咱們的 car 就生產好啦,貌似很簡單嘛。網絡

嘟嘟~車開着正起勁的時候,有位客戶說了,不喜歡自動生產的汽車,想請個專業人員整一輛定製 car。這時候有人說這還不簡單,噼裏啪啦的敲敲敲,代碼修改以下:ide

Creater:定製 car 的製做者:函數

public class Creater {
    private String name;//汽車製造者名字
    private String carType;//d定製 car 的類型

    public Creater(String name, String carType) {
        this.name = name;
        this.carType = carType;
    }
    public String createCar(){
        return this.carType;
    }
}

CarAutoCreate 製造汽車的技術封裝接口的實現類:oop

public class CarAutoCreate implements CarCreateTechnology {
    private Creater mCreater;//定製 car 的製做者

    public CarAutoCreate(Creater creater) {
        mCreater = creater;
    }

    @Override
    public String createCar() {
        return mCreater.createCar();
    }
}

CarFactory 汽車工廠類:ui

public class CarFactory {
    private CarCreateTechnology mCreateTechnology;

    public CarFactory(Creater creater) {
        mCreateTechnology = new CarAutoCreate(creater);
    }
    public String createCar(){
        return mCreateTechnology.createCar();
    }
}

最後 調用 String car = new CarFactory(new Creater("張少林", "寶馬")).createCar();咱們的定製 car "寶馬" 就被製造出來啦。這樣修改起來貌似挺簡單的,可是存在如下一些問題this

分析問題

  • CarFactory 類 依賴 CarAutoCreate 類。須要在 CarFactory 中持有 CarAutoCreate 實例。而咱們在 CarFactory 的構造中強行初始化了 CarAutoCreate,這就使得 CarFactory 與 CarAutoCreate 牢牢耦合在一塊兒。這就是傳說中的硬初始化(hard init)
  • 一旦 CarAutoCreate 的構造發生了變化,好比上面咱們增長了 Creater .這使得 CarFactory 也要被迫作出修改。
  • 這種耦合度在程序相對簡單的狀況下,修改也就修改嘛,ide 打代碼挺快的,可是一旦程序變得愈來愈複雜,依賴 CarAutoCreate 的地方很是多的狀況下,修改起來就不辣麼容易了,咱們須要付出至關多的勞動力去修改代碼,浪費時間不說,還頗有可能由於修改失誤而形成難以查找的錯誤,加大咱們的工做量。
知道了問題所在,咱們來想辦法解決,畢竟不喜歡偷懶的程序員不是好程序員,咱們須要寫出一手優雅的代碼。

解決問題——依賴注入

java 中常見的依賴注入有三種:

1、做爲構造函數的參數注入

咱們修改一下 CarFactory 的構造,將 CarCreateTechnology 做爲參數傳入,在構造中初始化全局 CarCreateTechnology 。

public class CarFactory {
    private CarCreateTechnology mCreateTechnology;

    public CarFactory(CarCreateTechnology createTechnology) {
        mCreateTechnology = createTechnology;
    }

    public String createCar(){
        return mCreateTechnology.createCar();
    }
}

調用:String car = new CarFactory(new CarAutoCreate(new Creater("張少林", "寶馬"))).createCar();結果是同樣的,定製 car 同樣制形成功。可是不一樣的是:咱們沒有在 CarFactory 構造中直接構造所依賴的類(CarAutoCreate),而是經過傳入形參,由最終調用方去初始化依賴類,這樣就解決了以前的硬初始化問題,實現瞭解耦,提升了程序的可拓展性、可維護性。 眼毒的同窗確定發現了,咱們的 CarAutoCreate 就是經過構造方法依賴注入所需的依賴(Creater)。

2、提供 Setter 設置值注入

CarFactory 添加 setxxx 注入全局變量。

public class CarFactory {
    private CarCreateTechnology mCreateTechnology;

    public void setCreateTechnology(CarCreateTechnology createTechnology) {
        mCreateTechnology = createTechnology;
    }

    public String createCar(){
        return mCreateTechnology.createCar();
    }
}

調用:

CarFactory carFactory = new CarFactory(); 
 carFactory.setCreateTechnology(new CarAutoCreate(new Creater("張少林","寶馬")));
 String car = carFactory.createCar();

這種方法也是提供方法設置屬性進去,一樣也沒有直接在 CarFactory 中直接實例化依賴類,而是最終調用的時候初始化設置進去,一樣達到解耦目的。

3、接口注入

接口注入跟 Setter 注入相似,只是用接口包裝了 Sertter 方法。這種方式易於管理。

public interface InjectTechnology {
    void injectCreate(CarCreateTechnology carCreateTechnology);
}

CarFactory 實現接口。複寫方法。在方法中注入。、

public class CarFactory implements InjectTechnology{
    private CarCreateTechnology mCreateTechnology;

    public String createCar(){
        return mCreateTechnology.createCar();
    }

    @Override
    public void injectCreate(CarCreateTechnology carCreateTechnology) {
        this.mCreateTechnology = carCreateTechnology;
    }
}

"硬編碼" 和 "軟編碼",圖片來自網絡

編碼方式區別.png

最後,應該有的思考

咱們在 oop 編碼設計中,應該儘量的讓依賴類在最上層初始化,在細節中杜絕硬編碼。編寫解耦,有可拓展性、可維護性的代碼。

更多原創文章會在公衆號第一時間推送,歡迎掃碼關注 張少林同窗

張少林同窗.jpg

相關文章
相關標籤/搜索