一、题目
在IoC模式中,被注入对象是通过哪种方式来通知IoC Service Provider为其提供适当服务的呢?
二、思考
2.1 个人
在Spring揭秘习题2.1:IOC模式场景中,已经举例出获取新闻信息场景。其中获取新闻方法(FXNewsListener)和保存新闻方法(FXNewsPersistent)都是可放入IoC Service Provider中供其他方法调用的。此处可以通过注解、getter或者是获取字段(IoCServiceProvider.FXNewsListener)形式拿到我们想要的对象。
可以先把IoCServiceProvider设计为一个已包含所有要调用类的静态类,这个类中已经实例化好所有待调用的实例。
1)注解方式是扫码注解后,去IoCServiceProvider中遍历搜索出是否包含该注解修饰的字段,若有则对此字段进行附值。
2)getter是在要使用的地方调用IoCServiceProvider.get(待获取类)即可。
3)获取字段是调用IoCServiceProvider.待获取类 即可。
2.2 Spring 揭秘
《Spring揭秘》-王福强 并未直接引入IoCServiceProvider,而是以更基础的方式来解决如何避免新生成实例,通过注入的方式把想要的实例注入其中。其采用了Martin Fowler的一篇文章“Inversion of Control Containers and the Dependecy Injection pattern”描述IOC模式。如下:
提到三种依赖注入的方式,即构造方法注入(constructor injection)、setter方法注入(setter injection)和接口注入(interface injection)。
三、解决
以Spring揭秘思路实现:
package com.demo.spring.chapter02.E2_IoCServiceProvider;
import java.util.Map;
import com.demo.spring.chapter02.E1_fxNews.FXNewsListener;
import com.demo.spring.chapter02.E1_fxNews.FXNewsPersistent;
public class FXNewsProviderIoC implements FXNewsListenerCallable{
private FXNewsListener fxNewsListener;
private FXNewsPersistent fxNewsPersistent;
private IFXNewsListener ifxNewsListener;
//1. 构造方法传入实例
public FXNewsProviderIoC(FXNewsListener fxNewsListener, FXNewsPersistent fxNewsPersistent){
this.fxNewsListener = fxNewsListener;
this.fxNewsPersistent = fxNewsPersistent;
}
//2. setter方式传入实例
public void setFxNewsListener(FXNewsListener fxNewsListener) {
this.fxNewsListener = fxNewsListener;
}
public void setFxNewsPersistent(FXNewsPersistent fxNewsPersistent) {
this.fxNewsPersistent = fxNewsPersistent;
}
//3. 接口注入方式
public void injectNewsListener(IFXNewsListener ifxNewsListener) {
this.ifxNewsListener = ifxNewsListener;
}
public void providNews(){
Map fxNewsContent = fxNewsListener.getFXNewsContent();
if(null != fxNewsContent){
fxNewsPersistent.persistentNewsContent(fxNewsContent);
}
System.out.println("展示存储后的结果" + fxNewsPersistent.getPersistentNewsContent());
}
}
package com.demo.spring.chapter02.E2_IoCServiceProvider;
public interface FXNewsListenerCallable {
void injectNewsListener(IFXNewsListener ifxNewsListener);
}
四、对比&优化
4.1 接口注入
缺点:强制被注入对象实现不必要的接口,带有侵入性。
优点:能解决问题。
4.2 构造方法注入
缺点:当内部依赖很多个类时,那构造方法的入参就需要很多个参数,后续再添加类时,也不利于维护。另一方面,构造方法不能被继承,无法设置默认值。
优点:在对象构造完成后,对象即进入就绪状态,可以马上使用。
4.3 setter方法注入
缺点:在对象构造完成后,不能立马使用这个对象,还需要调用一次set方法将依赖的实例注入到该类中。
优点:可以被继承。因为方法可以命名,所以在解释描述方面要比构造方法好些。
4.4 IoC带来的更多优势
场景1:现在实现IFXNewsListener接口的有2家报社,如果要加入第3家报社时,引入IoC和不引入IoC有哪些区别呢?
分析:如果不引入IoC,那就需要对每个报社新建一个FXNewsProvider类,因为每个报社都有一个 报社_FXNewsListener 的类,FXNewsProvider要对每个报社都初始化个实例出来。但如果使用IoC,FXNewsProvider的入参仅仅是IFXNewsListener接口类型即可,在真正使用时,将不同报社的 报社_FXNewsListener 作为入参传入到FXNewsProvider就能实现订阅该报。
优势:解决了重复写FXNewsProvider逻辑的问题。可重用了。
场景2: TDD,自己写测试脚本时,如果没有IoC,那么FXNewsProvider不能直接测不同报社的异常信息情况。如果有IoC就能直接mock出一个实现IFXNewsListener的MockFXNewsListener类即可,MockFXNewsListener可以当作参数传入到FXNewsProvider中。不会破坏原有的FXNewsProvider中的逻辑。
结构:题目、思考、解决、结果、对比&优化、参考