这是我参与更文挑战的第2天,活动详情查看:更文挑战
IoC全称Inversion of Control,控制反转,也叫做依赖注入(Dependency Injection)。那么,为什么需要IoC?IoC的具体意义是什么?让我们来引入一个简单场景来解释。
在一个外汇交易(FX)项目中,需要实时地为客户提供外汇新闻,通常情况下,需要先从不同的新闻社订阅新闻来源,然后通过批处理程序定时地到指定新闻服务器抓取最新的外汇新闻,接着将这些新闻存入本地数据库中,最后在前端显示。
假设由FXNewsProvider来完成以上工作
public class FXNewsProvider {
private IFXNewsListener newsListener;
private IFXNewsPersister newsPersister;
public void getAndPersistNews(){
String[] newsIds = newsListener.getAvailableNewsIds();
if (newsIds.length == 0) return ;
for (String newsId : newsIds){
FXNewsBean newsBean = newsListener.getNwesByPK(newsId);
newsPersister.persistNews(newsBean);
newsListener.postProcessIfNecessary(newsId);
}
}
}
FXNewsProvider依赖 newsListener来抓取新闻,newsPersister存储新闻,所以需要在构造函数中构造这两个依赖类
public FXNewsProvider(){
newsListener = new DJNewsListener();
newsPersister = new DJNewPersister();
}
在没有IoC之前,我们通常是以上这种做法。每次用到什么依赖对象都要主动地去获取,这真的必要嘛?我们最终要做的只是调用依赖对象提供的服务而已。所以IoC就是帮我们做了这些和业务逻辑无关的事情。
在IoC模式中,被注入的对象又是通过哪些方式来通知上图中的女生(IoC Service Provider)来为其提供适当的服务的呢?在权威文章中总结了有三种依赖注入的方式:1.构造方法注入 2.setter方法注入 3.接口注入
1.构造方法注入
public FXNewsProvider(IFXNewsListener newsListener, IFXNewsPersister newsPersister){
this.newsListener = newsListener;
this.newsPersister = newsPersister;
}
2.setter方法注入
public class FXNewsProvider {
private IFXNewsListener newsListener;
private IFXNewsPersister newsPersister;
public IFXNewsListener getNewsListener() {
return newsListener;
}
public void setNewsListener(IFXNewsListener newsListener) {
this.newsListener = newsListener;
}
public IFXNewsPersister getNewsPersister() {
return newsPersister;
}
public void setNewsPersister(IFXNewsPersister newsPersister) {
this.newsPersister = newsPersister;
}
}
3.接口注入 在这种情况下,实现的接口和接口中声明的方法名都不重要,重要的是接口中声明方法的参数类型,必须是”被注入对象“所依赖对象的类型。
三种方式的比较 接口注入:从注入方式的使用上来说,接口注入是现在不提倡的一种方式,基本处于”退役“状态。因为它强制被注入对象实现不必要的接口,带有侵入性。
构造方法注入:优点是,对象在构造完成之后,即已经进入就绪状态,可以马上使用。缺点是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反射构造对象时,对相同类型的参数处理会比较困难,维护也比较麻烦。
setter方法注入:因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好。另外setter方法可以被继承,允许设置默认值,有良好的IDE支持。缺点就是无法在构造完成后马上进入就绪状态。