文章目錄
先看看依賴倒置原則的原始定義:
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語言中,抽象就是指接口或抽象類,兩者都是不能直接被執行個體化的;細節就是實作類,實作接口或繼承抽象類而産生的類就是細節,其特點就是可以直接被執行個體化。
依賴倒置原則在Java語言中的表現就是:
● 子產品間的依賴通過抽象發生,實作類之間不發生直接的依賴關系,其依賴關系是通過 接口或抽象類産生的;
● 接口或抽象類不依賴于實作類;
● 實作類依賴接口或抽象類。
采用依賴倒置原則可以減少類間的耦合性,提高系統的穩定性,降低并行開發引起的風險,提高代碼的可讀性和可維護性。
以司機駕駛奔馳車為例:
3-1:司機駕駛奔馳車類圖
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CZ2kzYhhDOkNTN2QWMyUjYiRmZ0QmYwUWZhRjY4YTMy8CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
奔馳車提供一個方法run,代表車輛運作。
奔馳車類:
public class Benz {
//汽車會跑
public void run(){
System.out.println("奔馳汽車開始運作...");
}
}
司機通過調用奔馳車的run方法開動奔馳車.
司機類:
public class Driver {
//司機的主要職責就是駕駛汽車
public void drive(Benz benz){
benz.run();
}
}
有車,有司機,在Client場景類産生相應的對象.
場景類:
public class Client {
public static void main(String[] args) {
Driver zhangSan = new Driver();
Benz benz = new Benz(); //張三開奔馳車
zhangSan.drive(benz);
}
}
以上實作了司機開車的場景,在功能上是沒有問題。
現在新的需求來了,司機不僅要開奔馳車,還要開寶馬車。
寶馬車類:
public class BMW {
//寶馬車當然也可以開動了
public void run(){
System.out.println("寶馬汽車開始運作...");
}
}
現在發現問題了,司機沒有開動寶馬車類的方法,怎麼辦?給司機類添加開寶馬車的方法嗎?如果接下來司機要開挖掘機呢?在這裡,司機類和奔馳車類之間是緊耦合的關系,其導緻的結果就是系統的可維護性大大降低。
這時候就應該引入依賴倒置原則。
3-2:引入依賴倒置原則後的類圖
建立兩個接口:IDriver和ICar,分别定義了司機和汽車的各個職能,司機實作現drive()方法。
司機接口:
public interface IDriver {
//老司機,會開車
public void drive(ICar car);
}
司機實作類:實作IDriver接口:
public class Driver implements IDriver{
//司機的主要職責就是駕駛汽車
public void drive(ICar car){
car.run();
}
}
在IDriver中,通過傳入ICar接口實作了抽象之間的依賴關系,Driver實作類也傳入了ICar 接口,至于到底是哪個型号的Car,需要在高層子產品中聲明。
汽車接口及兩個實作類:
public interface ICar {
public void run();
}
//奔馳汽車類
public class Benz implements ICar{
public void run(){
System.out.println("奔馳汽車開始運作...");
}
}
//寶馬汽車類
public class BMW implements ICar{
public void run(){
System.out.println("寶馬汽車開始運作...");
}
}
業務場景類:
public class Client {
public static void main(String[] args) {
IDriver zhangSan = new Driver();
ICar benz = new Benz();
//張三開奔馳車
zhangSan.drive(benz);
ICar bmw = new BMW();
//張三開寶馬車
zhangSan.drive(bmw);
}
}
在新增加低層子產品時,隻修改了業務場景類,也就是高層子產品,對其他低層子產品如 Driver類不需要做任何修改,業務就可以運作,把“變更”引起的風險擴散降到最低。
依賴是可以傳遞的,A對象依賴B對象,B又依賴C,C又依賴D——隻要做到抽象依賴,即使是多層的依賴傳遞也是沒有絲毫問題的。
對象的依賴關系有三種方式來傳遞,如下所示:
在類中通過構造函數聲明依賴對象,按照依賴注入的說法,這種方式叫做構造函數注入,按照這種方式的注入,對IDriver和Driver進行修改。
public interface IDriver {
//司機就會開車
public void drive();
}
public class Driver implements IDriver{
private ICar car;
//構造函數注入
public Driver(ICar _car){
this.car = _car;
}
//司機的主要職責就是駕駛汽車
public void drive(){
this.car.run();
}
}
在抽象中設定Setter方法聲明依賴關系,依照依賴注入的說法,這是Setter依賴注入,按照這種方式的注入,對IDriver和Driver進行修改:
public interface IDriver {
//車輛型号
public void setCar(ICar car);
//是司機就應該會駕駛汽車
public void drive();
}
public class Driver implements IDriver{
private ICar car;
public void setCar(ICar car){
this.car = car;
}
//司機的主要職責就是駕駛汽車
public void drive(){
this.car.run();
}
}
在接口的方法中聲明依賴對象,未修改的IDriver和Driver就采用了接口聲明依賴的方式,該方法也叫做接口注入。
public interface IDriver {
//老司機,會開車
public void drive(ICar car);
}
public class Driver implements IDriver{
//司機的主要職責就是駕駛汽車
public void drive(ICar car){
car.run();
}
}