軟體設計原則—依賴倒轉原則

燕子去了發表於2024-05-19

高層模組不應該依賴低層模組,兩者都應該依賴其抽象;抽象不應該依賴細節,細節應該依賴抽象。

簡單的說就是要求對抽象進行程式設計,不要對實現進行程式設計,這樣就降低了客戶與實現模組間的耦合。

image

下面看一個例子來理解依賴倒轉原則:組裝電腦

現要組裝一臺電腦,需要配件cpu,硬碟,記憶體條。只有這些配置都有了,計算機才能正常的執行。選擇cpu有很多選擇,如Intel,AMD等,硬碟可以選擇希捷,西數等,記憶體條可以選擇金士頓,海盜船等。

image

希捷硬碟類XiJieHardDisk)

package com.lmcode.principles.DependenceInversionPrinciple;

// 希捷硬碟
public class XiJieHardDisk {
    public void save(String data) {
        System.out.println("使用希捷硬碟儲存資料" + data);
    }

    public String get() {
        System.out.println("使用希捷希捷硬碟取資料");
        return "資料";
    }
}

Intel處理器IntelCpu

package com.lmcode.principles.DependenceInversionPrinciple;

// Intel處理器
public class IntelCpu {
    public void run() {
        System.out.println("使用Intel處理器");
    }
}

金士頓記憶體條KingstonMemory

package com.lmcode.principles.DependenceInversionPrinciple;

// 金士頓記憶體條
public class KingstonMemory {
    public void save() {
        System.out.println("使用金士頓作為記憶體條");
    }
}

電腦Computer

package com.lmcode.principles.DependenceInversionPrinciple;

public class Computer {
    private XiJieHardDisk hardDisk;
    private IntelCpu cpu;
    private KingstonMemory memory;

    public IntelCpu getCpu() {return cpu;}
    public void setCpu(IntelCpu cpu) {this.cpu = cpu;}
    public KingstonMemory getMemory() {return memory;}
    public void setMemory(KingstonMemory memory) {this.memory = memory;}
    public XiJieHardDisk getHardDisk() {return hardDisk;}
    public void setHardDisk(XiJieHardDisk hardDisk) {this.hardDisk = hardDisk;}

    public void run() {
        System.out.println("計算機工作");
        cpu.run();
        memory.save();
        String data = hardDisk.get();
        System.out.println("從硬碟中獲取的資料為:" + data);
    }
}

測試類main用來組裝電腦。

package com.lmcode.principles.DependenceInversionPrinciple;

public class main {
    public static void main(String[] args) {
        // 建立元件物件
        XiJieHardDisk xiJieHardDisk = new XiJieHardDisk();
        IntelCpu intelCpu = new IntelCpu();
        KingstonMemory kingstonMemory = new KingstonMemory();
        // 建立電腦物件
        Computer computer = new Computer();
        // 組裝
        computer.setCpu(intelCpu);
        computer.setHardDisk(xiJieHardDisk);
        computer.setMemory(kingstonMemory);
        // 執行
        computer.run();
    }
}

上面程式碼可以看到已經組裝了一臺電腦,但是似乎組裝的電腦的cpu只能是Intel的,記憶體條只能是金士頓的,硬碟只能是希捷的,這對使用者肯定是不友好的,使用者有了機箱肯定是想按照自己的喜好,選擇自己喜歡的配件。

根據依賴倒轉原則進行改進:

程式碼我們只需要修改Computer類,讓Computer類依賴抽象(各個配件的介面),而不是依賴於各個元件具體的實現類。

image

物件導向的開發很好的解決了這個問題,一般情況下抽象的變化機率很小,讓使用者程式依賴於抽象,實現的細節也依賴於抽象。即使實現

細節不斷變動,只要抽象不變,客戶程式就不需要變化。這大大降低了客戶程式與實現細節的耦合度。

cpu介面,硬碟介面,記憶體條介面

package com.lmcode.principles.DependenceInversionPrinciplePro;

//cpu介面
public interface Cpu {
//    執行cpu
    public void run();
}
package com.lmcode.principles.DependenceInversionPrinciplePro;

// 硬碟介面
public interface HardDisk {
//    儲存資料
    public void save(String data);
//    獲取資料
    public String get();
}

package com.lmcode.principles.DependenceInversionPrinciplePro;

//記憶體條介面
public interface Memory {
    public void save();
}

實現類

package com.lmcode.principles.DependenceInversionPrinciplePro;

// Intel處理器
public class IntelCpu implements Cpu{
    public void run() {
        System.out.println("使用Intel處理器");
    }
}
package com.lmcode.principles.DependenceInversionPrinciplePro;

// 金士頓記憶體條
public class KingstonMemory implements Memory{
    public void save() {
        System.out.println("使用金士頓作為記憶體條");
    }
}
package com.lmcode.principles.DependenceInversionPrinciplePro;

// 希捷硬碟
public class XiJieHardDisk implements HardDisk{
    public void save(String data) {
        System.out.println("使用希捷硬碟儲存資料" + data);
    }

    public String get() {
        System.out.println("使用希捷硬碟取資料");
        return "資料";
    }
}

Computer

此時宣告元件不能宣告具體的實現類,而是父介面型別的抽象

package com.lmcode.principles.DependenceInversionPrinciplePro;

public class Computer {
    //    宣告元件不能宣告具體的實現類,而是父介面型別的抽象
    private HardDisk hardDisk;
    private Cpu cpu;
    private Memory memory;

    public HardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(HardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public Memory getMemory() {
        return memory;
    }

    public void setMemory(Memory memory) {
        this.memory = memory;
    }

    public void run() {
        System.out.println("計算機工作");
        cpu.run();
        memory.save();
        String data = hardDisk.get();
        System.out.println("從硬碟中獲取的資料為:" + data);

    }
}

main

package com.lmcode.principles.DependenceInversionPrinciplePro;

public class main {
    public static void main(String[] args) {
        // 建立元件物件
        HardDisk hardDisk = new XiJieHardDisk();
        Cpu cpu = new IntelCpu();
        Memory memory = new KingstonMemory();
        // 建立電腦物件
        Computer computer = new Computer();
        // 組裝
        computer.setCpu(cpu);
        computer.setHardDisk(hardDisk);
        computer.setMemory(memory);
        // 執行
        computer.run();
    }
}

此時加入需要換cpu,只需要建立一個cpu的類,實現cpu介面,然後再main中建立新的cpu然後作為引數傳遞

相關文章