IoC容器的核心原理与机制
IoC是个通用的设计机制,DI(依赖注入)则是具体的设计模式,它体现了IoC的设计原则。DI是IoC的最典型的实现,因此术语上IoC和DI经常混淆使用。
面向对象设计的基本思想是将系统分解为一组可重用的对象。如果没有一个核心模块来管理这些对象,它们将不得不各自创建和管理自己的依赖。结果就是这些对象会紧紧地耦合在一起。解决的方法就是,提供一个容器来管理组成系统的对象。该容器集中创建对象,并以注册表的形式提供对象的查找服务。同时,它还管理对象的生命周期,并为这些对象提供一个运行平台。运行于容器的对象必须遵循容器所定义的规范。
1、假设现在要实现打印报表这个功能,打印报表可生成Html和Pdf格式等不同类型。根据面向对象设计的“接口与实现分离”的原则,类图如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//接口ReportG public interface ReportG { public void getReport(); } //HtmlReport类 public class HtmlReport implements ReportG { @Override public void getReport() { // TODO Auto-generated method stub //do something } } //PdfReport类 public class PdfReport implements ReportG { @Override public void getReport() { // TODO Auto-generated method stub //do something } } //ReportService类 public class ReportService { private ReportG report = new HtmlReport(); //耦合 public void remove() { report.getReport(); //... } public void display() { report.getReport(); //.... } }
2,采用容器
类图修改为:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Contain类 import java.util.HashMap; import java.util.Map; public class Contain { public static Contain instance; private Map<String,Object> comps; //装入组件的容器 public Contain() { instance = this; comps = new HashMap<String,Object>(); //依次装入 ReportG ht = new HtmlReport(); comps.put("htmlReport", ht); ReportG pdf = new PdfReport(); comps.put("pdfReport", pdf); ReportService rs = new ReportService(); comps.put("reportService", rs); } public Object getComponent(String id) { return comps.get(id); } } //修改ReportService类 public class ReportService { private ReportG report = (ReportG)Contain.instance.getComponent("htmlReport"); public void remove() { report.getReport(); //... } public void display() { report.getReport(); //.... } }
3、在ReportService类中是直接查询ReportG的,可以将查询的部分封装,这样能增加组件的重用性以及降低查询复杂性。
类图修改为:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//ServiceLocate类 public class ServiceLocate { private static Contain contain = Contain.instance; public Object getReportG(String id) { return contain.getComponent(id); } }
4、应用控制反转和依赖注入
传统的资源查找方式要求组件向容器发起请求来查找资源,作为回应,容器适时的返回资源。而应用IoC后,则是容器主动地将资源推送到它所管理的组件里,组件要做的就是选择一种合适的方式来接受资源。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//修改Contain类 import java.util.HashMap; import java.util.Map; public class Contain { private Map<String,Object> comps; //装入组件的容器 public Contain() { comps = new HashMap<String,Object>(); ReportG ht = new HtmlReport(); ReportService rs = new ReportService(); rs.setReportG(ht); comps.put("rs", rs); } public Object getComponent(String id) { return comps.get(id); } } //修改ReportService类 public class ReportService { private ReportG report; public void setReportG(ReportG report) { this.report = report; } public void remove() { report.getReport(); //... } public void display() { report.getReport(); //.... } }
除了用set方法,叫做setter注入,还可以构造器注入,就是在ReportService的构造器中写入setReportG方法中的代码。