题记:纯菜鸟,也在慢慢学习中。博客更主要是为了博主自己日后回顾复习,当然也欢迎大家指正。
原来校招时候,面试各种JAVA后台的时候刷过一道题——
思考:写段代码实现控制反转
当时的感觉自然是一脸懵逼——额,我连题目都闹不明白呢,咋实现呢?
【我是答案,不标准但差不多是这个意思】所谓控制反转,就是由其他外部实体将原来控制主体需要的成员等信息生成好提供给他,而不再是简单地去持有依赖对象的引用。主体对原来的内部对象不再由其静态地了解,而是由外部实体将依赖对象注入或者说提供给这个主体。显然,主体只需要自己需要什么类型的成员就可以了,至于具体依赖的是谁,不需要自己知道。 为什么这么做呢?直观地一点就是充分解耦,注入的对象的生命周期不再由控制主体决定了。
当然解耦不是说没耦合,你毕竟用到了其余的对象,还是相互联系的,只是这种静态关系变成动态的了,因为是函数运行时候注入的嘛,原来可是没关系的。另一点就是更加利于模块化调试了。你用不到这个依赖对象的时候,依赖对象实现的代码理论上随便改,可以热插拔,具体用到的时候再去提供给他就好。
}
}
这种写法估计做安卓的小伙伴们会很熟悉吧,java按钮button组件最常用这种匿名内部类的实现了。实际上这就是一种控制反转的思想,因为本身按钮该做什么应该是按钮自身的内部函数吧~而实际上你在实现的时候,传入的是一个new好的Listener对象参数,而做事的,是Listener中被Override的方法。
通过这种方法,实现了控制各类Button的点击方法。
上简单的例子代码吧:
首先是被注入依赖的类的定义如下:
package IoCModel;
public class ControlBody {
private BodyListener listener=null;
public void setListener(BodyListener listener) {
this.listener = listener;
}
public void setOffListener(){
listener=null;
}
public void Work(){
if(listener!=null){
listener.doSomething();
}
else{
System.out.println("没有动态绑定的事件!");
}
}
}
看这个简单的片段,三点说明:
1.这个类持有真正做事的接口的一个对象Listener(具体实现对象)
2.这个类设置了如何设置做事的对象。
3.这个类真正做事的方法work实际上调用的是具体实现对象Listener的方法。
之后是定义对外接口的代码,这个很简单了,就一个抽象方法:
package IoCModel;
public interface BodyListener {
void doSomething();
}
最后是测试代码:
public class MainTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ControlBody body = new ControlBody();
body.setListener(new BodyListener() {
@Override
public void doSomething() {
System.out.println("我在做第一件事啊!"+this.toString());
}
});
body.Work();
body.setOffListener();
body.Work();
body.setListener(new BodyListener() {
@Override
public void doSomething() {
System.out.println("我又在做另一件事情啊!"+this.toString());
}
});
body.Work();
}
}
实现很简单粗暴吧?就是匿名内部类生成覆盖doSomething方法的不同实例而已。
咱要写的高雅一点,不妨可以直接再声明单独的类或者内部类去做事,然后具体哟个的时候,只需要在body.setListener()函数里把参数传成具体类的实例即可。
显然,如果我有一个BodyListener接口的A类实现,那注入的以来就是A类依赖对象,相互作用的是A类和调用类ControlBody;
如果我又有一个BodyListener接口的B类实现,那注入的以来就是B类依赖对象,相互作用的是B类和调用类ControlBody,这时候你A类爱怎么改怎么改,和主体调用无关了,你自行编译吧,我主体代码无需更改。
这也就是java多态的魅力呢。