控制反转(IOC)和依赖注入(DI)
IoC — Inversion of Control,控制反转
DI — Dependency Injection,依赖注入
IOC,是一种设计原则:
通过将组件(Components)的设置和使用分开,来降低类别或模组之间的耦合度(即,解耦)
Martin Fowler,因认为“IoC”的意义易使人困惑,于2000年初,与多位IoC提倡者,给实际实践IOC的方式起一个更具体的名称— — “Dependency Injection (依赖注入)”。
控制反转IOC
控制反转,指实例依赖成员的『控制流程(Control Flow)』,由主动控制变成被动控制,因此被称为控制反转。
举个例子
小明有一台iPhone手机,他写了个程序来控制这个iphone手机来抢红包,自动发短信,自动抢购等等,这些过程可以用如下方式简单描述:
- 打开iPhone,打开微信,进入群聊,抢红包
- 打开iPhone,打开短信,编辑短信内容,选择收件人,发送短信
- 打开iPhone,打开小米商城,选择需要抢购的商品,等待到达抢购时间,开始抢购
- ······
大家很容易就能看出来问题,这些过程和iPhone耦合的很紧密,如果小明需要换手机了,那么那需要在每个过程中都将iPhone换为新手机。这时,就需要控制反转,我们不再主动去获得手机,而是被动的接收一个手机。
这样这些流程就可以更改为:
- 接收手机
- 打开手机,打开微信,进入群聊,抢红包
- 打开手机,打开短信,编辑短信内容,选择收件人,发送短信
- 打开手机,打开小米商城,选择需要抢购的商品,等待到达抢购时间,开始抢购
这样,我们发现,过程和具体的一个手机(例如,iPhone)耦合度降低了,可以很简单的更改手机的实例。
另一个例子
我们去网咖打游戏,是不可能自己带游戏去网咖的,而是网咖都把这些游戏提供好了。
需要的游戏,不用自己下载,而是网咖提供给你。
==>
需要的依赖实例,不用主动(Active)建立,而是被动(Passive)接收。
这就是控制反转(Inversion of Control)
简单来说,A依赖B,但A无法控制B的创建和销毁,仅使用B,那么B的控制权交给C(A以外)处理
- 第一个例子,小明是A,依赖手机B,C可以是其他任何给小明手机的人(可能有点牵强)
- 第二个例子,我们是A,依赖游戏B,C则是网吧
依赖注入DI
刚才那两个例子中,小明需要手机,我们需要玩游戏,那么有哪些方法可以让我们被动接收这些东西呢?假设小明是A,手机是B
- 通过A的接口,把B传入
- 通过A的构造,把B传入
- 通过设置A的属性,把B传入
这个过程就是依赖注入,即A啥都没干,就可以直接使用B,比如我们啥也不用干,就可以直接玩游戏,真香。
也可以说,依赖注入是实现控制反转的一种方式,它们之间有着密切的联系
依赖倒置原则DIP
实际上,之前所说的控制反转是非常像:
依赖倒置原则(Dependency Inversion Principle, DIP)
这个原则是指,高阶模块不要依赖低阶模块,而是依赖抽象。
比如:
- 我们喜欢吃油泼面
- 我们也喜欢吃鱼香肉丝盖饭
- 我们还喜欢吃江边城外烤全鱼
- ······
那么,这些如果写到代码里,将会是非常紧密的耦合,假如有一天我们不喜欢吃油泼面,或者无法吃到油泼面,则代码非常多的地方需要更改
因此可以进一步抽象,
- 我们喜欢吃面,我们→面←油泼面
- 我们也喜欢吃盖饭,我们→盖饭←鱼香肉丝盖饭
- 我们还喜欢吃烤鱼,我们→烤鱼←江边城外烤全鱼
- ······
还可以更进一步的抽象
- 我们喜欢吃食物,我们→食物←面,盖饭,烤鱼······
我们真正所需要的、依赖的,其实不是实际的类别与物件,而是它所拥有的功能。 其实这就是依赖倒置原则DIP (Dependency Inversion Principle)
进一步地:
- 高阶模块不应该依赖于低阶模块,两者都该依赖抽象
- 抽象不应该依赖于具体实现方式
- 而是具体实作方式应该依赖抽象
实际上,面向接口编程就是一个具体地实践方法
IoC 容器(IoC Container)
IoC容器(又称:服务容器Service Container),随着依赖注入的频繁使用,来实现控制反转,会有很多重复代码,甚至随着技术的发展,有更多新的实现方法和方案,那么有人就把这些实现控制反转的代码打包成组件或框架,来避免人们重复造轮子。
广义上来说, IoC容器,就是有进行依赖注入的地方,你随便写一个类别,透过它将所需元件注入给高阶模组,便可说是容器。
但现在所说的『容器』,往往是泛指那些强大『框架』的容器
- 动态生成实例,create,resolve,make等,为当前实例注入依赖
- 注册依赖关系,利用配置或其他方式查找依赖关系,例如bind,register,link
- ······