IoC顾名思义为“控制反转”,就是反转资源获取的方向,容器主动将资源注入到它所管理的组件里,组件所要做的工作仅仅是选择一种合适的方式接受资源。而传统的思维方式是:当一个组件需要外部资源时,组件会向容器发送查找资源的请求,容器再将找到的资源传送给该组件。由此开来IoC的优势是组件不需要知道如何获取资源,只需要选择接受资源的方式,从而降低的模块之间的耦合度,也是体现出这种设计原则优点。
说道IoC就不得不说DI(依赖注入),其实他们的设计思想是相同的,不过DI是IoC的一个良好的实现。下面来说说DI所做的工作:
在DI模式下,容器全权负责组件的装配工作,容器会将一些之前定义好的方式(如setter方法或构造函数)将匹配的资源注入到每个组件里。
.setter注入 setter注入会存在一些问题,1.容易出现忘记调用setter方法注入组件所需要的依赖,将会导致NullPointetException异常。2.代码会存在安全问题,第一次注入后,不能阻止再次调用setter,除非添加额外的处理工作。
.构造器注入 构造器注入能够一定程度上解决setter注入的问题。但是该注入方式也会带来一些问题,如果组件有很多的依赖,则构造函数的参数列表将会变得冗长,会降低代码的可读性。
.接口注入 该注入的方式使用的非常少,它要求组件必须实现某个接口,容器是透过这个接口实现注入依赖的。接口注入的缺点比较明显,使用接口注入需要实现特定的接口,而接口又特定与容器,所以组件对容器产生依赖,一旦脱离容器,组件不能重用。这是一种“侵入式”注入。
由此可见常用到的注入方式是:setter和构造器注入
/*生成报表的通用接口*/public interface ReportBuilder{ public void build(String data);}
/*生成HTML格式报表*/public class ReportHtmlBuilder implements ReportBuilder { @Override public void build(String data) { /*示意代码*/ System.out.println("build html report!"); }}/*生成PDF格式报表*/public class ReportPdfBuilder implements ReportBuilder { @Override public void build(String data) { System.out.println("build pdf report!"); }}
/*报表服务类*/public class ReportService { /*依赖"ReportBuilder"*/ private ReportBuilder builder; public ReportBuilder getBuilder() { return builder; } /*setter注入*/ public void setBuilder(ReportBuilder builder) { this.builder = builder; } public void builderYearReport(int year) { this.builder.build("data"); }}
//IoC容器配置文件"component.properties"pdfBuilder=com.beliefbitrayal.ioc.inter.imp.ReportPdfBuilderhtmlBuilder=com.beliefbitrayal.ioc.inter.imp.ReportHtmlBuilderreportService=com.beliefbitrayal.ioc.server.ReportServicereportService.builder=htmlBuilder
//IoC容器public class Container{ /*用于储存Component的容器*/ private Maprepository = new HashMap (); public Container() { try { /*读取容器配置文件"component.properties"*/ Properties properties = new Properties(); properties.load(new FileInputStream("src/component.properties")); /*获取配置文件的每一行信息*/ for(Map.Entry
//根据配置文件,我们在场景类中使用的报表应该是HTML格式的:public class Client{ public static void main(String[] args) { /*创建容器*/ Container container = new Container(); /*从容器中获取"报表服务类"*/ ReportService reportService = (ReportService)container.getComponent("reportService"); /*显示报表*/ reportService.builderYearReport(0); }}