一个简单的例子
Ioc(Inversion of Control),控制反转。名字起得比较高大上,事实上是一种工程思想,不仅适用于编程领域。我用一个简单的例子来说明IoC:
假设我们到一个餐馆里去吃饭,这个餐馆有成百上千个厨师,每位厨师只能做一样菜,这时候客人应该怎样点菜?
- 直接到厨房去寻找厨师,找到对应的厨师做菜
- 向服务员下单,由服务员将菜式需求统一报给对应厨师烹饪
正常思维都会选择第二种方法,然而我们之前的编程经常采用第一种方法:定义好类后,在执行的主程序中直接创建对应对象进行使用。假如有成百上千个对象,那基本就崩了。
于是我们考虑第二种方法的设计:
- 安排几个服务员,A服务员负责点面,B服务员负责点炒饭,C服务员负责点汤
- 由A服务员对接所有面食厨师,B服务员对接所有炒饭厨师,C服务员对接所有汤水厨师。
联系到Java的语言特性不难想到:
实现IoC的核心特性是:多态。
下面用一张图来表示这种设计:
真正的IoC
上面的图,并不是我们讨论的真正意义上的IoC。大家网上常见的分析IoC的文章一般都使用齿轮图,上面这张图则倾向于一个金字塔结构。事实上,我们将这幅图重新绘制一下,就能和齿轮图联系起来了:
在之前的顾客和厨师的基础上,我加入了老板、保洁员、仓储物流等元素。也就是说,我们还可以实现类似以下的需求:
-
老板通过服务员联系保洁进行清洁
-
老板通过服务员联系仓储物流管理食材储备
-
......
我们把那张齿轮图拿来看一下:
联系上图的图,现在马上就能反应过来IoC容器扮演了什么样的角色了。它不是金字塔的某一层,而是所有相关业务的处理枢纽。
还剩下一个问题,为什么称其为“容器”呢?看Java代码实现就能明白为什么了:
// 服务员实现类
public class ServerImpl implements Server {
// 采用组合的方式引入noodles
private Noodles noodles;
@Override
public void getNoodles() {
// 代理模式
noodles.getNoodles();
}
@Override
public void setNoodles(String noodles) {
if("兰州拉面".equals(noodles)){
this.noodles = new LanZhouNoodles();
}else if("热干面".equals(noodles)){
this.noodles = new HotDryNoodles();
}else{
this.noodles = null;
}
}
}
// 测试代码
Server server = new ServerImpl();
server.setNoodles("热干面");
server.getNoodles();
这是一个服务员的实现类,可以看出是一个面食服务员。通过组合的方式引入noodles类型,由此就可以使用noodles的成员方法了。
作为顾客而言,关心的是吃的什么面,而不是谁来烹饪这碗面。从测试代码来看是调用了Server的内部方法setNoodles和getNoodles,事实上getNoodles是Noodles类的方法,但这对于顾客来说不重要。所以服务员实现类内部对noodles的成员方法进行了再封装:
public void getNoodles() {
noodles.getNoodles();
}
在设计模式中称之为代理模式。
由此推及其他可得:服务员需要处理什么,就在实现类的内部利用组合的方式加入什么。由于是作为成员变量而存在的,所以其也被形象地称之为容器。