Spring Recipse精译(1)

 

第一章    IOC 和容器

1-1    使用容器管理组件

【问题】

面向对象设计的原理之一就是要将对象分组以重用。但如果没有一个统一的模块管理这些对象,而由它们自身管理创建和依赖,会引起对象间的紧耦合。

【方案】

使用容器来组织你的系统。容器将负责对象整个生命周期的管理和查找服务。

【详细】

接口和实现分离

例如你开发的系统有提供不同类型报表的功能,如 HTML PDF 。针对面向对象设计的接口和实现分离原理,应该为生成报表定义一个公用的接口。假设报表由两维的表格数据生成。定义的接口如下:

Public interface ReportGenerator{

              Public void generate(String[][] table);

}

接着建立两个类 HtmlReportGenerator PdfReportGenerator 来实现 ReportGenerator 接口。

Public class HtmlReportGenerator implements ReportGenerator{

       Public void generate(String[][] table){

              System.out.println(“Generating HTML report”);

}

}

Public class PdfReportGenerator implements ReportGenerator{

       Public void generate(String[][] table){

              System.out.println(“Generating PDF report”);

}

}

建立服务类 ReportService ,由它提供多种报表服务。

Public class ReportService{

       Private ReportGenerator reportGenerator = new PdfReportGenerator();

       Public void generateAnnualReport(int year){

              String[][] statistics = null;

              //Gather statistics for the year

              reportGenerator.generator(statistics);

}

Public void generateMonthlyReport(int year, int month){

    String [][] statistics = null;

//Gather statistics for the monthe

    reportGenerator.generate(statistics);

}

}

如下 UML 图说明了现在的 ReportService 类和 ReportGenerator 实现类的依赖关系

这会引起 ReportService ReportGenerator 实现间的直接依赖关系。

  Spring Recipse精译(1)

 

引入容器

引入容器来管理对象。

Public class Container{

    //The global instance of this Container class for the components to locate.

    Public static Container instance;

    //A map for storing the components with their IDs as the keys

    Private Map<String, Object> components;

    Public Container(){

           Components = new HashMap<String, Object>();

Instance = this;

ReportGenerator  reportGenerator = new PdfReportGenerator();

Components.put(“reportGenerator”, retportGenerator);

 

ReportSerice reportServie= new ReportSerice();

Component.put(“reportService”, reportService);

}

Public Object  getComponent(String id){

    Return components.get(id);

}

}

加入容器后 ReportService 如下

Public class ReportServie{

  Private ReportGenerator reportGenerator = (ReportGenerator);                         Container.instance.getComponent(“reportGenerator”);

Public void generateAnnualReport(int year){ . . .

}

. . .

}

UML 图如下


Spring Recipse精译(1)

可以看到 ReportSerice 这时依赖与容器,而容器依赖与 ReportGenerator 的实现。

 

测试类

Public class main{

       Public static void main(String[] args){

              Container container = new Container();

              ReportService reportService = (ReportService) container.getComponent(“reportService”);

              reportService.generateAnnualReport(2010);

}

}

 

1-2    使用服务定位器降低查找的复杂度

【问题】

在容器的管理下,组件依赖于它们的接口,而不是实现。需要硬编码。

【方案】

为降低查找组件的复杂度,引入服务定位器模式。用一个服务定位器来封装复杂的查找逻辑。

【详细】

Public class ServiceLocator{

       Private static Container container = Container.instance;

       Public static ReportGenerator getReportGenerator(){

       Return (ReportGenerator) container.getComponent(“reportGenerator”);

}

}

在服务类中可以直接使用服务定位器查找依赖对象。

Public class ReportSerice{

       Private ReportGenerator reportGenerator =

              ServiceLocator.getReportGenerator();

       Public void generatorAnnualReport(int year){

      

}

}

UML 类图如下:


Spring Recipse精译(1)

 

1-3    应用 IoC DI

【问题】

当组件需要一个外表的资源,如数据源。最直接的方式是进行查找。我们称这种方式为主动查找。如服务定位器。

【方案】

更好的获取资源的方式是使用 IoC 。思想是反转资源获取的方向。在典型的查找中,组件向容器发送请求查找,容器返回查找资源。在 IoC 中,容器主动向被管组件分发资源。一个组件只能被动的接受资源。这被称之为被动查找。

IoC 是理论上的概念,而 DI 依赖注入是具体的设计模式。在 DI 模式中,容器负责为每个组件,在预先决定的方式,注入适当的资源。

【详细】

依据 DI 模式,在 ReportService 中为 ReportGenerator 属性加入 setter 方法。

Public class ReportService{

       Private ReportGenerator reportGenerator; // No need to look up actively

       Public void setReportGenerator(ReportGenerator reportGenerator){

       This.reportGenerator = reportGenerator;

}

       Public void generatorAnnualReport(int year){

      

}

}

 

Public class Container{

       //No need to expose itself for the components to locate

       //public static Container instance

       Private Map<String , Object> components;

Public Container(){

              Components = new HashMap<String, Object>();

              //No need to expose the current instance of container

              //instance = this;

ReportGenerator reportGenerator = new PdfReportGenerator();

Components.put(“reportGenerator”, reportGenerator);

ReportService reportService = new ReportService();

reportService.setReportGenerator(reportGenerator);

components.put(“reportService”, reportService);

}

Public Object getComponent(String id){

       Return components.get(id);

}

}


Spring Recipse精译(1)


IoC 原理就是俗称的好莱坞原理。

不要给我打电话,我会给你打电话的。

 

1-4    理解不同类型的 DI

【问题】

需要不同的 DI 类型

【方案】

三种类型:

接口注入

Setter 注入

构造器注入

【详细】

Setter 注入

Setter 注入是最常用的注入类型。通过组件中的 setter 方法注入它的依赖。

 

构造器注入

通过组件的构造器注入它的依赖。

 

接口注入

基本上不用这种方式。

 

1-5   用配置文件配置容器

【问题】

使用容器来管理组件以及它们的依赖关系时,配置信息如果使用硬编码方式,不易于维护。

【方案】

使用基于文本的、语义强的 XML properties 文件。它们不需要重新编译。