依賴注入

github https://github.com/spring2go/core-spring-patterns.gitgit

依賴倒置原則 (Dependency Inversion Principle)

  • SOLID面向對象原理之一
    • 高層模塊不該該依賴底層模塊。二者都應該依賴於抽象
    • 抽象不該該依賴於細節。細節應該依賴於抽象。
  • 總結:就是面向接口編程

只要接口不變,就能夠任意更換設備

  1. 主機就是高層模塊,剝露不少接口,接口就是抽象
  2. 接口不依賴於設備,設備依賴於接口,不依賴於主機。

問題:高層模塊依賴於底層模塊,不利於擴展,若是擴展須要修改代碼
  1. 若是止時,不發送日誌了,須要發送短信,此時就須要修改代碼
// 高層模塊
public class AppMonitorNoDIP {

    // 負責將事件日誌寫到日誌系統
    private EventLogWriter writer = null;
    
    // 應用有問題時該方法將被調用
    public void notify(String message) {
        if (writer == null) {
            writer = new EventLogWriter();
        }
        writer.write(message);
    }
    
    public static void main(String[] args) {
        AppMonitorNoDIP appMonitor = new AppMonitorNoDIP();
        appMonitor.notify("App has a problem ...");
    }
}

// 底層模塊
class EventLogWriter {
    public void write(String message) {
        // 寫到事件日誌
        System.out.println("Write to event log, message : " + message);
    }
}

使用依賴倒置原則改進 關係圖

  • 高層模塊不該該依賴底層模塊。二者都應該依賴於抽象。
  • 抽象不該該依賴於細節。細節應該依賴於抽象。
// 事件通知器接口
public interface INotifier {
    public void notify(String message);
}

// 發送短消息
public class SMSSender implements INotifier {
    public void notify(String message) {
        System.out.println("Send SMS, message : " + message);
    }
}

// 寫到事件日誌
public class EventLogWriter implements INotifier {
    public void notify(String message) {
        System.out.println("Write to event log, message : " + message);
    }
}

// 發送Email
public class EmailSender implements INotifier {
    public void notify(String message) {
        System.out.println("Send email, message : " + message);
    }
}

依賴倒置DIP 客戶端調用

  • 高層模塊不依賴於底層接口,依賴於抽象
public class AppMonitorIOC {
    // 事件通知器
    private INotifier notifier = null;
    
    // 應用有問題時該方法被調用
    public void notify(String message) {
        if (notifier == null) {
            // 將抽象接口映射到具體類
            notifier = new EventLogWriter(); (這裏有耦合性,須要new出來)
        }
        notifier.notify(message);
    }
    
    public static void main(String[] args) {
        AppMonitorIOC appMonitor = new AppMonitorIOC();
        appMonitor.notify("App has a problem ...");
    }
}

控制反轉( Inversion of Control)

  1. 傳統作法: 主程序的依賴和裝配都是由主程序驅動的
  2. 依賴注入作法:當須要依賴對象時,由依賴注入器運行期注入進來

依賴注入(Dependency Injection)具體實現

  • 構造函數注入
  • Setter注入
  • 接口注入

構造函數注入

public class AppMonitorConstructorInjection {
    // 事件通知器
    private INotifier notifier = null;
    
    public AppMonitorConstructorInjection(INotifier notifier) {
        this.notifier = notifier;
    }
    
    // 應用有問題時該方法被調用
    public void notify(String message) {
        notifier.notify(message);
    }
    
    public static void main(String[] args) {
        EventLogWriter writer = new EventLogWriter();
        AppMonitorConstructorInjection monitor = 
                new AppMonitorConstructorInjection(writer);
        monitor.notify("App has a problem ...");
    }
    
}

spring ioc 依賴注入

  1. 定義元數據運行時的依賴關係
  2. spring ioc 在運行期,將須要的依賴注入進來

好處

  • 依賴解耦
    • 模塊化:不僅直接new
    • 易於測試
    • 易於變化和擴展
相關文章
相關標籤/搜索