你須要知道的依賴注入

如題,你是否常常聽人提起依賴注入?反正筆者對這個概念已經聽過屢次,也去搜索瞭解了許多知識,但每次看完都感受有點繞,因而作了一些實戰來便於理解。前端

  • 依賴注入的前置知識
  • 非依賴注入的開發模式
  • 依賴注入的開發模式
  • 依賴注入容器的開發模式

更多文章,歡迎 Star 和 訂閱 個人博客mysql

依賴注入的前置知識

要了解依賴注入,必須得先知道如下知識點。git

  • 依賴倒置
  • 控制反轉
  • 依賴注入

依賴倒置 DIP

依賴倒置(Dependency inversion principle,縮寫爲 DIP)是面向對象六大基本原則之一。它是指一種特定的解耦形式,使得高層次的模塊不依賴於低層次的模塊的實現細節,依賴關係被顛倒(反轉),從而使得低層次模塊依賴於高層次模塊的需求抽象。github

該原則規定:web

  • 高層次的模塊不該該依賴於低層次的模塊,二者都應該依賴於抽象接口。
  • 抽象接口不該該依賴於具體實現。而具體實現則應該依賴於抽象接口。

上面這兩句話很抽象,須要細細品味才能發現其中奧祕,若是暫時理解不了也不要緊,下文會結合具體案例幫助你們理解。sql

控制反轉 IOC

控制反轉(Inversion of Control,縮寫爲 IOC)是面向對象編程中的一種設計原則,用來下降計算機代碼之間的耦合度。是實現依賴倒置原則的一種代碼設計思路。其中最多見的方式叫作依賴注入,還有一種方式叫依賴查找。數據庫

依賴注入 DI

依賴注入(Dependency Injection,縮寫爲 DI)是實現控制反轉的一種方式。經常使用的依賴注入方法有 3 種:編程

  • 接口注入
  • 構造函數注入
  • 屬性注入

案例介紹

在瞭解了相關理論以後,接下來咱們經過案例來理解一下依賴注入。後端

經常使用的後端架構能夠分爲 3 層:架構

  • web 層
    • 接收前端請求,處理請求參數,匹配後端路由,調用對應的 service 層處理業務。
  • service 層
    • 接收 web 層的參數,處理業務邏輯,若是須要讀取數據,會調用 database 層。
  • database 層
    • 處理數據庫相關的層,負責鏈接數據庫,以及經常使用的增刪改查方法的封裝。

接下來咱們經過非依賴注入依賴注入依賴注入容器這 3 種思路,搭建一個簡單的後端 3 層架構。

非依賴注入的開發模式

非依賴注入的開發模式很符合常規邏輯,即:web 層依賴 service 層,service 層依賴 database 層。

案例以下:

// 案例中使用僞代碼,便於你們理解。
class Database {
  select(sql) {
    const mysql = require('mysql');
    return new Promise(resolve => {
      // 鏈接數據庫,並執行 sql 語句進行查詢
      mysql.createConnection().query(sql, (error, results, fields) => {
        const success = results.length > 0 ? true : false;
        resolve(success);
      });
    });
  }
}

class Service {
  async login(username, password) {
    const db = new Database();
    const success = await db.select(
      `select * from user where username=${username} and password=${password}`
    );
    return success ? '登陸成功' : '登陸失敗';
  }
}

class Web {
  matchRouter(path) {
    switch (path) {
      case 'login':
        const service = new Service();
        const { username, password } = path.query;
        return service.login(username, password);
    }
  }
}

// 使用 web 層
const web = new Web();
web.matchRouter('login');
複製代碼

上面的代碼是典型的高層次模塊依賴低層次模塊案例。web 層依賴 service 層,service 層依賴 database 層。

非依賴注入開發模式的優缺點:

  • 代碼複雜度低,邏輯清晰,使用方便,直接 new 最上層的模塊就好了。
  • 不利於維護,若是底層( database 層)修改了 select 方法的傳參方式,上層(service 層和 web 層)也必須同步修改調用方式。
  • 不利於測試,各個模塊耦合在一塊兒,要單獨測試 web 層是不行的,由於它內部引入了 service 層和 database 層,只能當成一個總體測試。

依賴注入的開發模式

若是把上面的案例改形成依賴注入的方式也很簡單,刪除內部依賴關係,將須要的依賴經過構造函數注入就好了。

// 案例中使用僞代碼,便於你們理解。
class Database {
  select(sql) {
    const mysql = require('mysql');
    return new Promise(resolve => {
      // 鏈接數據庫,並執行 sql 語句進行查詢
      mysql.createConnection().query(sql, (error, results, fields) => {
        const success = results.length > 0 ? true : false;
        resolve(success);
      });
    });
  }
}

class Service {
  constructor(db) {
    this.db = db;
  }
  async login(username, password) {
    // const db = new Database();
    const success = await this.db.select(
      `select * from user where username=${username} and password=${password}`
    );
    return success ? '登陸成功' : '登陸失敗';
  }
}

class Web {
  constructor(service) {
    this.service = service;
  }
  matchRouter(path) {
    switch (path) {
      case 'login':
        // const service = new Service();
        const { username, password } = path.query;
        return this.service.login(username, password);
    }
  }
}

// 使用 web 層以前,必須手動建立依賴,並注入
const database = new Database();
const service = new Service(database);
const web = new Web(service);
web.matchRouter('login');
複製代碼

上面的代碼能夠看出,web 層並不直接依賴 service 層,而是經過構造函數將 service 傳進來直接用,這就實現了依賴注入的效果。

依賴注入開發模式的優缺點:

  • 代碼複雜度低,邏輯清晰,使用較複雜,須要手動注入依賴。
  • 便於維護,代碼耦合度低,各個模塊互不依賴。
  • 便於測試,不一樣模塊之間能夠單獨的進行單元測試。

依賴注入容器的開發模式

若是使用上面的案例,每一次使用都須要手動傳入依賴,當依賴太多時,也會形成難以維護的問題。咱們能夠在一個地方統一進行依賴注入,即在一個依賴注入容器裏。

一個簡單的依賴注入容器以下:

// ioc.js
export default function createIoC() {
  const iocMap = new Map();
  return {
    bind(key, callback) {
      iocMap.set(key, { callback });
    },
    use(key) {
      const { callback } = iocMap.get(key);
      return callback();
    }
  };
}
複製代碼

在統一的配置文件中配置依賴關係。

// ioc-config.js
import createIoC from 'ioc.js';
const ioc = createIoC();

// 手動綁定依賴關係
ioc.bind('Database', () => {
  return new Database();
});

ioc.bind('Service', () => {
  const database = ioc.use('Database');
  return new Service(database);
});

ioc.bind('Web', () => {
  const service = ioc.use('Service');
  return new Web(service);
});

export default ioc;
複製代碼

使用容器注入依賴。

import ioc from 'ioc-config.js';
// 使用 web 層
const web = ioc.use('Web');
web.matchRouter('login');
複製代碼

上面代碼使用 IOC 容器來進行依賴注入,優缺點以下:

  • 代碼複雜度較高,邏輯較複雜,使用方便,要什麼就注入什麼就好了。
  • 便於維護,只需在一個地方(ioc-config.js)定義依賴關係,這個文件能夠抽離出來做爲單獨的配置文件,實現數據驅動。
  • 便於測試,不一樣模塊之間能夠單獨的進行單元測試。

總結

  • 依賴倒置是面向對象的基本原則。
  • 控制反轉是實現依賴倒置原則的一種代碼設計思路。
  • 依賴注入是實現控制反轉的一種方式。

依賴注入

本文經過非依賴注入,依賴注入,IOC 容器這 3 種開發模式來分析了依賴注入的開發方式。加深了筆者對依賴注入的理解,但願經過這個案例能讓更多的同窗弄懂依賴注入。

相關連接

更多文章,歡迎 Star 和 訂閱 個人博客

相關文章
相關標籤/搜索