依賴倒置原則 - DIP, Dependence Inversion Principle
爲軟件設計六大設計原則之一,定義如下:
上層模塊不應該依賴底層模塊,它們都應該依賴於抽象。
抽象不應該依賴於細節,細節應該依賴於抽象。
上層模塊不應依賴底層模塊,即上層的業務模塊不應該依賴底層的實現模塊。如:人出行使用交通工具,只需要知道是交通工具就可以,不用知道是哪種具體的交通工具。
抽象不應該依賴於細節,細節應該依賴於抽象。在java編程中,抽象指代接口、抽象函數,統稱爲接口,而細節指代接口的具體實現。
因此,依賴倒置原則即爲面向接口編程的原則。
示例:
交通工具類:
public interface Driveable {
void drive();
}
class Bike implements Driveable{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("Bike drive.");
}
}
class Car implements Driveable{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("Car drive.");
}
}
Person類:
public class Person {
private Driveable mDriveable;
public Person() {
mDriveable = new Train();
}
public void chumen() {
System.out.println("出門了");
mDriveable.drive();
}
}
Person中使用接口Driveable來定義交通工具,出行依賴的是交通工具接口,而不是具體的交通工具。這樣,我們可以自由的選擇交通工具,只要該交通工具實現該接口,並將其傳遞給Person類中的Driveable接口。 這就是面向接口編程的好處。
好處:可擴展性比較好,以後添加其他交通工具不影響現在代碼。即抽象不依賴於細節。
控制反轉 - IOC, Inversion of Control
問題:Person中還是需要創建具體交通工具,並用其初始化Driveable接口。
Person自己要負責創建具體交通工具,而且要關心交通工具創建成功與否。如果放在現實生活中,這是一件特別荒謬的事情。Person實際上只需要使用具體交通工具,製造廠才需要創建具體交通工具。對於Person來說,你只要提供給我交通工具,我使用就好了。這就引出了控制反轉的概念,即Person不需要自己創建其依賴的交通工具,交通工具只需要在外面創建好,給Person就好了。
控制反轉下Person類的實現:
public class Person {
private Driveable mDriveable;
public Person(Driveable driveable) {
mDriveable = driveable;
}
public void chumen() {
System.out.println("出門了");
mDriveable.drive();
}
}
使用Person類:
public class Test {
public static void main(String[] args) {
Train train = new Train();
Person person = new Person(train);
person.chumen();
}
}
這樣,交通工具在創建Person的時候傳遞給Person類就好,完全解放了Person類。這樣,出現新的交通工具,或需要改變Person使用的交通工具,都不需要修改Person類。
IoC, 控制反轉是Spring框架中的一個重要思想,即依賴方不需要關心被依賴對象的創建,只需要使用傳進來的被依賴對象即可。IoC結合面向接口編程,可以使得編寫的程序擴展性更強。
依賴注入 - DI , Dependency Injection
依賴注入是實現控制反轉的一個手段,通過配置文件xml,annotation-based或java-based的方式來實現,是Spring中的核心概念。 關於具體怎麼實現DI,可以參考我之前的文章Spring - DI .