// 案例中使用伪代码,便于大家理解www.duidaima.com。 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 层。
3.不利于测试,各个模块耦合在一起,要单独测试 web 层是不行的,因为它内部引入了 service 层和 database 层,只能当成一个整体测试。
// 案例中使用伪代码,便于大家理解www.duidaima.com 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 传进来直接用,这就实现了依赖注入的效果。
3.便于测试,不同模块之间可以单独的进行单元测试。
// 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 容器来进行依赖注入,优缺点如下: