`
wsjjasper
  • 浏览: 13252 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

2.基于Spring的应用程序的设计和实现(接口驱动设计)

阅读更多

接口驱动设计

 

 

接口驱动设计几乎已经成为了一种实现应用程序的习惯,无论是框架还是你使用的一些标准(Spring,jboss,guice,EJB等等)。这样设计的一个主要目标是进一步的简化应用程序开发。在详细讨论设计细节之前,有必要阐述下为什么这样设计如此重要,以及spring是如何简化它的。

 

为什么要接口驱动设计

 

设计成接口驱动而不是直接使用类有很多原因,但也许最重要的原因就是降低耦合。如果一个容器使用接口来编写,当它有问题时将很容易被替换。这项特性将使你能够方便的将一种实现转为另一种,而不需要影响其他的代码。事实上,这么做你甚至可以使你的程序可以使用多种不同的实现并存。比如,当你使用spring 的prifile特性时,你能够在不影响其他代码的情况下提供给一个接口以不同的实现。不仅如此,在java里,一个类只能继承一个父类却能够实现多个不同的接口。通过定义接口,你不用使用一个类去继承特定的类(非常大的抽象类),而是实现多个接口。另一个好处,如我们在第七章讨论的,当你使用面向切面思想时,使用接口驱动让你能够使用spring的introduction特性,从而在你的类中 “嵌入”特定的接口,同时又不影响其他代码和逻辑。


在测试方面,一个主要的好处是通过降低耦合使得测试更容易。作为开发者的一员,我们一直在寻求新的方式来改进我们的程序测试覆盖率。通过接口驱动设计,我们可以方便的使用模拟来替换那些接口实现,从而使我们的测试更灵活。比如,当我们做单元测试一个web controller的时候,我们只想关注是否这个controller工作正常,并且假定那些service都是没问题的。在这种情况下,使用模拟service将会非常的合适。

 

工厂模式

 

在实现程序时可能会碰到一个非常关键的问题:将所有的容器都定义为接口后,程序将如何确定它使用哪个实例?


一个传统的方法是使用工厂模式。工厂模式定义了那些用来实现接口的实现类。在这种情况下,容器是以接口定义而不是类定义的。假设有个业务接口叫OrderService。其他容器需要获得这个实例,但又不能确定何时要,该如何实现? 通常做法是创建一个工厂类如12-1代码。

 

 

//Listing 12-1. A Basic Factory Class Implementation
package com.apress.prospring3.ch12.factory;

import com.apress.prospring3.ch12.service.OrderService;
import com.apress.prospring3.ch12.service.impl.DefaultOrderServiceImpl;

public class BasicFactory {
	private static final BasicFactory instance;
	private OrderService orderService;
	static {
		instance = new BasicFactory();
	}

	public static BasicFactory getlnstance() {
		return instance;
	}

	public BasicFactory() {
		this.orderService = new DefaultOrderServiceImpl();
	}

	public OrderService getOrderService() {
		return this.orderService;
	}
}
 

 

这是个非常简单的工厂实现例子。现在程序要得到OrderService的实现只要使用BasicFactory的getOrderService()方法就可以了。

 

传统工厂模式的缺点

 

传统的工厂模式主要有如下三个缺点:


-除非重新编译,否则没法修改实现类


-容器没有办法简单的使用需要的实现类。容器必须对工厂类有所了解从而知道该调用工厂类的哪个方法来获得实现。


-无法简单的修改实现类。在12-1例子中,返回了一个的实例,但是假设我们想同时需要多个实例,我们不得不修改并重新编译工厂类,我们将在接下来的三个小节中对这些缺点的详细讨论

 

可外部配置的工厂类

 

在12-1的例子中,你可以看到修改实现类意味着修改并重新编译。接口驱动设计的一个好处就是可以方便的替换实现类。然而,重新编译工厂类使其大打折扣。在过去的许多工程中,那时还没有Spring, 我们通常创建一个可以在外部配置文件中配置的工厂类来避免这个问题。这的确解决了开头的问题,但是它也使得我们不得不承担更多的开发工作,更糟的是,即使如此还是有问题。。。

 

显示的多实现支持

 

显示的多实现支持也许是传统工厂模式最大的缺点。在类BasicFactory中,getOrderService()方法,只能返回唯一一个特定的实现,无法自由选择。于是很自然的我们想到了如12-2的实现方式:

 

 

//Listing 12-2. Basic Support for Multiple Implementations
package com.apress.prospring3.ch12.factory;

import com.apress.prospring3.ch12.service.OrderService;
import com.apress.prospring3.ch12.service.impl.DefaultOrderServiceImpl;
import com.apress.prospring3.ch12.service.impl.SuperOrderServiceImpl;

public class MultiFactory {
	private static final BasicFactory instance;
	private OrderService orderService;
	private OrderService superOrderService;
	static {
		instance = new BasicFactory();
	}

	public static BasicFactory getInstance() {
		return instance;
	}

	public MultiFactory() {
		this.orderService = new DefaultOrderServiceImpl();
		this.superOrderService = new SuperOrderServiceImpl();
	}

	public OrderService getOrderService() {
		return this.orderService;
	}

	public OrderService getSuperOrderService() {
		return this.superOrderService;
	}
}
 

 

在这种实现方式下,容器可以调用getSuperOrderService()方法来获得SuperOrderServiceImpl实例。然而,这种方式恰恰否定了工厂的好处。虽然容器没有与特定的实现类耦合,但是与工厂的方法耦合了。另一个缺点是每次添加新实现类的修改都得重新编译,这也很不方便。


另外一个解决方案是在调用getOrderService()方法时把类型传进去,根据传进去的类型来返回这个类型的实现类。这种方式也有很多问题,比如它只能通过类来工作,意味着两个相同类型的实例将无法实现。你将同时发现如果你有许多不同的实现类时,getOrderService()

方法将变得很大很难维护。


相对而言,一个比较好的办法是使用查找方式的方法来让容器选择需要的实现类。所以,不是调用getOrderService(),而是调用getOrderService("someKey")。但即使如此,问题还是存在,为了使得足够灵活,每个容器必须使用特定的key来获取实现,key将变得很多很难维护。而且当需要更新实现时,仍然得修改代码并编译。问题的症结在于容器必须自己去决定使用哪个实现类,所以无论如何,传统的工厂类都会遇到问题。

 

多个实例模型支持

 

另一个问题是我们的容器同时需要多个实现的实例。这个问题和刚才的一样,问题在于容器必须自己去决定使用哪个实现类。对返回类型都无法支持,对于返回的实例数量当然也是没有办法支持的。

 

基于Spring的接口驱动设计

 

    Spring的接口驱动设计对应用程序开发影响很大。因为它能统一管理所有的容器,你压根就不需要担心如何去设计工厂类来获得实现。


在表面看来,当你用spring构建一个接口驱动的程序时,最大的好处是你不用写大量冗余的代码。只需通过一些配置即可。其实,这都归功于spring的依赖注入机制。凭借它,spring去除了容器对于实现类的依赖,只要让容器运行spring注入即可。


依赖注入即是说spring能够提供一个实现类的实例给任何容器,同时不需要在容器中编写任何代码。这是因为spring可以自由的管理任何实现实例的完整生命周期。总之就是spring有我们需要的所有接口驱动设计所必须的特征,从而使我们从如何获得接口实现的问题中得以脱身。


下一节:基于Spring的应用程序的设计和实现(构建领域对象模型) http://wsjjasper.iteye.com/blog/1574590
 

分享到:
评论

相关推荐

    Spring中文帮助文档

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring API

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring.3.x企业应用开发实战(完整版).part2

    13.6.4 Web应用程序中调度器的启动和关闭问题 13.7 小结 第14章 使用OXM进行对象XML映射 14.1 认识XML解析技术 14.1.1 什么是XML 14.1.2 XML的处理技术 14.2 XML处理利器:XStream 14.2.1 XStream概述 14.2.2 快速...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

     国内知名的高端IT技术作家,已出版《Spring 2.0宝典》、《基于J2EE的Ajax宝典》、《轻量级J2EE企业应用实战》、《Struts 2权威指南》、《Ruby On Rails敏捷开发最佳实践》等著作。 目录: 第0章 学习Java...

    Spring3.x企业应用开发实战(完整版) part1

    13.6.4 Web应用程序中调度器的启动和关闭问题 13.7 小结 第14章 使用OXM进行对象XML映射 14.1 认识XML解析技术 14.1.1 什么是XML 14.1.2 XML的处理技术 14.2 XML处理利器:XStream 14.2.1 XStream概述 14.2.2 快速...

    JAVA核心知识点整理(有效)

    2.2.1. 程序计数器(线程私有) ................................................................................................................ 22 2.2.2. 虚拟机栈(线程私有) .................................

    基于Spring-boot和dubbox的API接口和后台管理系统.zip

    驱动程序:为特定硬件设备提供接口,使操作系统能够识别和控制这些设备。 实用工具:如编译器、链接器、调试器、文件管理器等,协助开发、维护和管理计算机系统。 应用软件: 办公套件:如Microsoft Office、...

    Java基于SSM(Spring+SpringMVC+MyBatis)作业提交与批改程序.zip

    基于java的实现MVC设计模式的请求驱动类型的轻量级Web框架,通过注解,无需实现任何接口,处理请求,支持restful。 三层结构:表现层、业务层、持久层 设计模式:Model(模型)、View(视图)、Controller(控制器) ...

    Spring攻略(第二版 中文高清版).part2

    12.4 更快地构建更好的应用程序 493 12.4.1 问题 493 12.4.2 解决方案 494 12.4.3 工作原理 494 12.5 从项目中删除Spring Roo 500 12.5.1 问题 500 12.5.2 解决方案 500 12.5.3 工作原理 501 12.6 ...

    Spring攻略(第二版 中文高清版).part1

    12.4 更快地构建更好的应用程序 493 12.4.1 问题 493 12.4.2 解决方案 494 12.4.3 工作原理 494 12.5 从项目中删除Spring Roo 500 12.5.1 问题 500 12.5.2 解决方案 500 12.5.3 工作原理 501 12.6 ...

    Java 面试宝典

    一. Java 基础部分............................................................................................................43、Java 中的异常处理机制的简单原理和应用。 .....................................

    基于Spring-boot和bootstrap搭建的商城系统.zip

    驱动程序:为特定硬件设备提供接口,使操作系统能够识别和控制这些设备。 实用工具:如编译器、链接器、调试器、文件管理器等,协助开发、维护和管理计算机系统。 应用软件: 办公套件:如Microsoft Office、...

    ssh(structs,spring,hibernate)框架中的上传下载

     文件数据存储在Blob类型的FILE_CONTENT表字段上,在Spring中采用OracleLobHandler来处理Lob字段(包括Clob和Blob),由于在程序中不需要引用到oracle数据驱动程序的具体类且屏蔽了不同数据库处理Lob字段方法上的...

    springmybatis

    其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细...

    基于java的企业级应用开发:Bean的装配方式.ppt

    2.5.2 基于Annotation的装配 基于Annotation装配的使用方式如下: JDBC驱动器:由数据库厂商创建,也称为JDBC驱动程序。负责与特定的数据库连接,以及处理通信细节。 创建接口UserDao,并定义方法; 创建接口实现类...

    SpringMVC笔记.zip

    SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架 ,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。...

    毕设之基于微信小程序的短文写作竞赛管理系统_ry--(源码+部署说明+SpringBoot+微信小程序+vue).zip

    基于微信小程序的短文写作竞赛管理系统是一个结合了当下流行技术栈的综合性项目。此系统主要采用了前后端分离的架构,后端使用SpringBoot进行搭建,前端则由微信小程序和Vue.js构成。下面将详细介绍所使用的技术和...

    领域驱动设计与模式实战

    2.4 针对具体应用程序类型的设计模式 2.5 领域模式 2.6 小结 第3章 TDD与重构 3.1 TDD 3.1.1 TDD流程 3.1.2 演示 3.1.3 设计效果 3.1.4 问题 3.1.5 下一个阶段 3.2 模拟和桩 3.2.1 典型单元测试 3.2.2 声明独立性 ...

Global site tag (gtag.js) - Google Analytics