基本介紹
- 高層模塊不應(yīng)該直接依賴底層模塊,應(yīng)該依賴其抽象。
- 細節(jié)應(yīng)該依賴抽象,抽象不應(yīng)該依賴細節(jié)。
- 依賴倒置的中心思想是面向接口編程。
- 相對于細節(jié)的多變性,抽象的東西更穩(wěn)定,以抽象為基礎(chǔ)搭建的架構(gòu)比以細節(jié)為基礎(chǔ)的架構(gòu)要穩(wěn)定的多。
- 使用接口或抽象類的目的是制定好規(guī)范,而不涉及任何具體的操作,把展現(xiàn)細節(jié)的任務(wù)交給他們的實現(xiàn)類去完成。
代碼示例
示例一(錯誤寫法)
public class DependenceInversion {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
// 電子郵件細節(jié)類
class Email {
public String getInfo() {
return "電子郵件信息為:Hello,World!";
}
}
// 模擬人接收消息
class Person {
public void receive(Email email) {
System.out.println(email.getInfo());
}
}
這是最簡單最容易想到的寫法,如果需要接收微信或者其它消息,則需要在person類新增接收的方法。所以可通過依賴倒置的方式解決,添加IReceiver接口做為緩沖層。
示例二(依賴倒置)
public class DependecyInversion {
public static void main(String[] args) {
//客戶端無需改變
Person person = new Person();
person.receive(new Email());
person.receive(new WeChat());
}
}
// 定義接口
interface IReceiver {
String getInfo();
}
class Email implements IReceiver {
@Override
public String getInfo() {
return "電子郵件信息: hello, world!";
}
}
// 增加微信
class WeChat implements IReceiver {
@Override
public String getInfo() {
return "微信信息: hello, world!";
}
}
// 方式2
class Person {
// 這里我們是對接口的依賴
public void receive(IReceiver receiver) {
System.out.println(receiver.getInfo());
}
}
引入抽象的接口IReceiver,Person類只與接口發(fā)生依賴關(guān)系,在調(diào)用的時候只需要傳入接口的實現(xiàn)類即可。
傳遞方式
1.接口傳遞
public class DependencyPass {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
OpenAndClose openAndClose = new OpenAndClose();
// 通過接口的實現(xiàn)類實現(xiàn)
openAndClose.open(changHong);
}
}
// 開關(guān)的接口
interface IOpenAndClose {
// 抽象方法,接收接口
void open(ITV tv);
}
// ITV接口
interface ITV {
void play();
}
class ChangHong implements ITV {
@Override
public void play() {
System.out.println("長虹電視機,打開");
}
}
// 實現(xiàn)接口
class OpenAndClose implements IOpenAndClose {
@Override
public void open(ITV tv) {
tv.play();
}
}
2.構(gòu)造方法傳遞
public class DependencyPass {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
// 通過構(gòu)造器進行依賴傳遞
OpenAndClose openAndClose = new OpenAndClose(changHong);
openAndClose.open();
}
}
class ChangHong implements ITV {
@Override
public void play() {
System.out.println("長虹電視機,打開");
}
}
interface IOpenAndClose {
void open(); //抽象方法
}
// ITV接口
interface ITV {
void play();
}
class OpenAndClose implements IOpenAndClose {
public ITV tv; // 成員
public OpenAndClose(ITV tv) { // 構(gòu)造器
this.tv = tv;
}
@Override
public void open() {
this.tv.play();
}
}
3.setter方法傳遞
public class DependencyPass {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
//通過setter方法進行依賴傳遞
OpenAndClose openAndClose = new OpenAndClose();
openAndClose.setTv(changHong);
openAndClose.open();
}
}
interface IOpenAndClose {
void open(); // 抽象方法
void setTv(ITV tv);
}
interface ITV { // ITV接口
void play();
}
class OpenAndClose implements IOpenAndClose {
private ITV tv;
@Override
public void setTv(ITV tv) {
this.tv = tv;
}
@Override
public void open() {
this.tv.play();
}
}
class ChangHong implements ITV {
@Override
public void play() {
System.out.println("長虹電視機,打開");
}
}
總結(jié)
- 底層模塊盡量都要有抽象類或接口,或者兩者都有,程序穩(wěn)定性更好。
- 變量的聲明類型盡量是抽象類或接口,這樣我們的變量引用和實際對象間就存在一個緩沖層,利于程序擴展和優(yōu)化。
- 繼承時遵循里氏替換原則。