IOC 控制反转()
控制反转 (inversion of control, 缩写 IOC), 是一种设计原则, 顾名思义,他是用于面向对象设计中的各种控件.
可以降低代码的耦合度, 使程序模块化,易于扩展, IOC意味着将依赖模块和被依赖模块都交给容器去管理,当我们使用模块的时候,由容器动态的将它的依赖关系注入到模块中,
正对上面的问题, 往往需要IOC模式, 一般使用DI(Dependency Injection) 依赖注入的方式实现.
以订单为例子, 先看美誉依赖注入的情况.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Order { constructor() {}
insert() { return true; } }
const Order = require("./Order.js");
class OrderController { constructor() { this.order = new Order(); }
createOrder(...args) { this.order.insert(...args); } }
const OrderController = require("./OrderController.js"); const orderController = new OrderController();
|
上面是没有依赖注入的情况, OrderController 类耦合了Order类, 在使用前必须require 引入 Order类才能使用,假如Order类发生了修改变化, 那么所有依赖这个Order类的文件都需要修改,
来在看看依赖注入的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Order { constructor() {}
insert() { return true; } }
const Order = require("./Order.js");
class OrderController { constructor(order) { this.order = order; }
createOrder(...args) { this.order.insert(...args); } }
const Order = require("../model/Order.js"); const OrderController = require("./OrderController.js"); const orderController = new OrderController(new Order());
|
可以看出依赖注入已经对模块进行了解耦,但是还是有不足之处, 下面总结一下依赖注入的优缺点:
优点: 通过依赖注入高层模块与底层模块耦合度降低,因此底层模块发生变化时,我们不需要了解底层模块发生的变化, 只需要管理router中依赖的路径.
不足:
我们所有依赖的模块都在router中引入,明显增加了router模块的复杂性, 我们需要一个专门管理注入及被注入的容器. 即我们常说的IOC 容器.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class IOC { constructor() { this.controller = new Map(); }
bind(key, callback) { this.controller.set(key, { callback, single: false }); }
sigleton(key, callback) { this.controller.set(key, { callback, single: true }); }
use(key) { const item = this.controller.get(key); if (!item) { throw new Error("error"); }
if (item.single && !item.instance) { item.instance = item.callback(); }
return item.single ? item.instance : item.callback(); } }
const Order = require("../model/Order.js"); const OrderController = require("./OrderController.js");
ioc.bind("order", (...args) => new Order(...args)); ioc.bind("orderController", (...args) => new OrderController(ioc.use("order")));
const ioc = require("../ioc.js"); const orderController = ioc.use("orderController");
|
上面就是一个简单的ICO 容器实现, 通过bind方法将模块间的依赖绑定到容器中,通过use方法判断模块是否存在,
若不存在则报错;
存在则判断是否实例化,已实例化不需要执行的callback().