- 浏览: 639513 次
- 性别:
- 来自: 北京
最新评论
-
2047699523:
java hibernate demo使用实例教程源代码下载: ...
hibernate延迟加载的原理与实现 -
在世界的中心呼喚愛:
hantsy 写道这种lazy的解释只对了一半,按java p ...
hibernate延迟加载的原理与实现 -
moguicy:
看了下时间,不是楼主是否还在开发
【翻译】Wicket启示录——理论与实践(一) -
xfan0828:
"最后但并不是最不重要的一点就是" BZ, ...
【翻译】深入浅出 EJB3.1(上) -
doudou87323:
十分感谢,正在学习中,受益匪浅
【翻译】深入浅出 EJB3.1(上)
本文的作者Danny hui似乎是TTS上的新人,我从Google搜不出一点关于本人的信息。从通过本文可以看出他对模式与IoC有自己独到的见解,本文在TTS上引发很多网友回帖,反响不一。那么我们现在来看看作者的IoC之路吧。
原文:http://www.theserverside.com/tt/articles/article.tss?l=InjectionwithAbstractFactory
简介
本文重点讨论的是DI(依赖注入)结合设计模式中的Abstract Factory(抽象工厂模式)的优势与弊端。该方式尤其适合以下场合:
l 通过dynamic parameters(动态参数)来建立一个local stateful对象
l 当创建对象时抛出了checked exception时进行相应处理,
l 动态的封装对象
像Spring IoC容器,PicoContainer以及Guice都无法圆满的解决这些问题或者说它们几乎做不到!!!
用Abstractory Factory模式来实现DI
现在通过下面两种途径来改进经典GoF中的Abstract Factory:
l 一个工厂接口来代替抽象工厂类(可行)
l 每一个工厂方法的职责就是创建对象,并为其注入依赖
来看一个简单的例子吧:
在这里,ComponentA依赖于ComponentB。为方便进行单元测试ComponentAImpl类,接口ComponentB的实现必须注入到ComponentAImpl中去。下面看看采用Abstract Factory模式完成依赖注入的Java实现代码:
//Abstract Factory for Dependency Injection
//Factory interface
public interface Module1ServiceFactory {
ComponentA getComponentA();
ComponentB getComponentB();
}
//Concrete factory
public class Module1ServiceFactoryImpl implements Module1ServiceFactory {
private ComponentA componentA;
private ComponentB componentB;
private Module1Servicefactory instance;
private Module1ServicefactoryImpl() {}
public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServicefactoryImpl();
componentA = new ComponentAImpl();
componentB = new ComponentBImpl();
componentA.setComponentB(componentB);
}
return instance;
}
public ComponentA getComponentA() {
return componentA;
}
public ComponentB getComponentB() {
return componentB;
}
}
//Client
public class Client {
public static void main(String[] args) {
Module1ServiceFactory m1sf =
Module1ServicefactoryImpl.getInstance();
ComponentA componentA = m1sf.getComponentA();
componentA.operationA1();
}
}
延迟加载
延迟加载对象可以通过改变方法来实现,比如说我现在要稍微对getComponentA()进行改动,请看:
public synchronized ComponentA getComponentA() {
if (null == componentA) {
componentA = new ComponentAImpl();
}
return componentA;
}
当然我们的Module1ServiceFactoryImpl.getInstance()方法也要进行相应的改动了,我们可以通过传递一个参数来判断Module1ServiceFactoryImpl.getInstance()是否需要创建对象。
非Singleton作用域
上面的代码仅仅只是建立singleton对象。如果需要在每次调用getComponentA()和getComponentB()的时,都返回新创建的对象的话,我们可以对我们的Abstract Factory进行下面的改动:
//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;
private Module1ServiceFactoryImpl() {}
public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
}
return instance;
}
public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB();
componentA.setComponentB(componentB);
return componentA;
}
public ComponentB getComponentB() {
return new ComponentBImpl();
}
}
类似的,我们还可以将一个singleton对象注入到非singleton对象中去。比如说,我们假设ComponentB此时是singleton,ComponentA为非singleton,那么我们可以这样:
//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;
private ComponentB componentB;
private Module1ServicefactoryImpl() {}
public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
componentB = new ComponentBImpl();
}
return instance;
}
public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
componentA.setComponentB(componentB);
return componentA;
}
public ComponentB getComponentB() {
return componentB;
}
}
将一个非singleton对象注入到singleton对象也不是做不到,但这种应用场合在现实世界中是非常罕见的。尽管如此,但在使用dynamic parameters赋级一个locallocal变量时,创建一个非singleton对象却很普遍。接下的话题,我们就谈谈这个。
用dynamic parameters为singleton创建一个local stateful对象
这是所有IoC框架所面临的问题。下面的代码中,仍然假定ComponentA为singletion:
public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = new ComponentCImpl(s, i);
//do something else.
}
这里,ComponentAImpl用到了ComponentC接口。虽然,为了更IoC,我们需要将它注入ComponentC的实现,而不是直接硬编码在ComponentAImpl.operationA2()方法中去,这样做还有一个好处就是,方便单元测试。但问题来了,我们不能将ComponentC作为一个实例变量,因为它是有状态的(stateful),它维持着某一个特定的客户端状态,不能与其它客户端进行共享。因此,不能使用常用的setter或construtctor注入方法来实现。
使用Abstract Factory模式的话,有两个方法可以解决这个问题。不过,都得改动Module1ServiceFactory接口,添加下面方法:
ComponentC getComponentC(String s, int i);
请看我在Module1ServiceFactoryImpl中的实现代码:
public ComponentC getComponentC(String s, int i) {
return new ComponentCImpl(s, i);
}
第一种方法就是将包含它的“工厂”注入到所需的local stateful对象中去:
private Module1ServiceFactory factory;
public void setModule1ServiceFactory(Module1ServiceFactory factory) {
this.factory = factory;
}
//ComponentAImpl.operationA2() becomes:
public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = factory.getComponentC(s, i);
//do something else.
}
缺点显而易见:ComponentAImpl现在与Module1ServiceFactory绑定在一起了,如果要对ComponentAImpl进行单元测试的话,我们不得不mock一个Module1ServiceFactory实现。纵然有这个缺陷,但直接为stateful对象注入“工厂”对象的方法也最为简单。类似的技术广泛的在J2EE领域采用,比如说JPA,将我们将entity manager factory可以注入到应用程序代码后,它就专门负责管理自身创建的application-managed entity。(注:如果熟悉Hibernate的话,也可以将entity manager factory想象成HibernateSessionFacory, application-managed entity想象成Session)
第二种方法就是将方法抽出,移到抽象类中去,便于单元测试:
public abstract class AbstractComponentA implements ComponentA {
public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = getComponentC(s, i);
//do something else.
}
public abstract ComponentC getComponentC(String s, int i) ;
}
public class ComponentAImpl extends AbstractComponentA {
public ComponentC getComponentC(String s, int i) {
return new ComponentCimpl(s, i);
}
}
这种方式类似于Springframework的方法注入(Metod Injection),不过Spring不需要传递dynamic parameter也能创建stateful对象。此时,单元测试可以不需要再实现任何mock工厂。但是,这仍然是一个笨拙的办法。设想一下,我们的类里如果有10个这样的local stateful对象,那么我们需要提供10个抽象方法,才能再次让单元测试变得简单,可是代价就造成是更加混乱的应用程序代码。
Springframework还可以通过使用Java反射机构还解决类似问题。但这更加复杂了,并且不适合正常应用程序编码工作。
处理创建对象时抛出的checked exceptions
这个问题也是让IoC容器头痛的。如果checked exception在对象创建时抛出,应用程序可能希望是能捕获并且能够恢复。我们来看一下这个关于Web Service的需求实例:当客户端尝试建立web service的stub时,并且此时服务端web service还不可用,那么客户端是能够捕获stub所抛出的异常,然后显示相应信息,并询问用户是否稍后继续再次连接。如果单纯用IoC容器的话,抛出具体指定的checked exception是很困难的。而手工代码却可以很轻松的解决这个问题——我们可以简单的将“工厂”的checked exceptions抛出,留给应用程序代码去手工处理或者恢复它们。
动态封装对象
很多场合下,一个接口对应着多个不同的实现类,类型实例就是设计模式中的策略模式。那么,用一个参数就可以决定具体哪个实现类应该被注入到相应的封装对象中去。然而使用基于XML和IoC容器是静态封装对象,很难实现此功能。也许编程式的IoC容器可以解决动态依赖问题,但我要说的是我们的Abstract Factory则更简单直接,看看下面的代码就知道了:
//Concrete factory
public class Module1ServiceFactoryImpl {
...
public ComponentA getComponentA(int strategy) {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB(strategy);
componentA.setComponentB(componentB);
return componentA;
}
public ComponentB getComponentB(int strategy) {
switch(strategy) {
case STRATEGYA:
return new StrategyA();
case STRATEGYB:
return new StrategyB();
default:
return null;
}
}
}
注意这里StrategyA和StrategyB共享实现了ComponentB接口。
结束语
今天我们谈到的运用依赖注入和Absratct Factory设计模式来解决下列问题:
1. 通过动态参数,创建local stateful对象
2. 处理创建对象时抛出的checked exceptions
3. 动态封装注入对象
除此以外,该方法与其它IoC容器相比,性能更好,毕竟是直接硬编码嘛。那么最大的缺点自然就是要手工写很多基础代码了,并且如果要延迟加载与主动加载之间来回切换的话,代码的改动量是很可观的。不过呢,这样的需求几乎是不存在的。
可单元测试的关键点是基于接口而非实体类编程。这样的话mock对象可以注入到任何需要注入的地方去。
不管怎么样,有时候在我们的应用程序中,依赖注入是一个不得不解决的问题。所有IoC容器以及手工的依赖注入解决方案都是专注于各自的领域——Spring IoC使用XML配置,Google Guice使用特殊的Java,我们的Abstract Factory也是如此。通过这些解决方案,我们可以避免应用程序中到处显现依赖的编码,类与类之间耦合度降低,使用Mock对象就可以正常进行单元测试。
对所有的IoC容器来说,无论是声明式的还是编程式的,它们的目的就是作为一个对象创建和封装工厂。同样我们的Abstract Factory也是如此,只不过这是一个可定制的依赖注入解决方案。
最后,使用IoC容器,我们可以消除类与类之间的依赖,从而让单元测试变得更加简单。但代价就是你不得不再次依赖于第三方Jar包或XML配置文件。IoC容器并没有一个统一的标准,每个框架所提供的特性和功能都是不同的,因为一旦你使用了某个IoC框架,就意味
评论
EJB3.1第三部分刚刚出来了,下次给大家介绍那个吧。
发表评论
-
【翻译】深入浅出 EJB3.1(下)
2009-05-07 23:37 8911Global JNDI names( 统一的 全局 ... -
【翻译】深入浅出 EJB3.1(上)
2009-05-06 20:59 11158终于有空将EJB3.1的最新文章与大家分享,原文请看: ht ... -
【翻译】Java EE 6体系结构的变革
2009-02-09 10:01 4525又看到 Reza 同学为 -
【翻译】Java EE 6体系结构的变革(完)
2009-02-09 10:00 6471JSF 2.0 尽 ... -
垃圾收集器是一个“宝贝收藏家”?
2008-11-25 23:58 3077原文请看:http://java.dzone.com/ar ... -
深入理解JBoss Cache3.0——Naga
2008-11-12 09:12 9741原文请看: http://java.dzone.com/ ... -
【翻译】Rod Johnson——关于当选JCP执行委员会的之言片语
2008-11-03 10:42 3189SpringSource 在上月底被宣布被加入 JCP ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(五) 终章
2008-10-16 14:37 9215历时9 个多月的EJB3.1 系列文章终于要划上圆满的句 ... -
【翻译】Rod Johnson——平衡的质疑:Spring维护策略的再次调整(完)
2008-10-09 09:33 4067不管你承不承认,Spring实际上已经是实事上JAVA企业开 ... -
【云计算专家Joseph Ottinger系列】应用服务器本质论
2008-09-08 08:58 3478原文请看: http://www.t ... -
Spring破坏了JEE规范吗?
2008-09-02 13:33 4094[TTS 编辑注:这是 TTS 论坛上的原帖。我现在把它 ... -
【翻译】spring配置全书(下)——附PDF完整版下载
2008-07-14 12:30 10840JMS 命名空间简介 Schema URI ... -
【翻译】spring配置全书(上)
2008-07-07 23:11 8947作者简介: Craig Walls 是 Texa ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(四)
2008-06-18 23:10 38218前言 Raza 同学终于又出 EJB3.1 文章了 ... -
【翻译】Rod Johnson——Spring的宣言:开源,开放(完)
2008-06-10 16:51 5614前言 这是本文的第二部分,里面提到并回答许多Spring用 ... -
【翻译】Rod Johnson——Spring的宣言:开源,开放
2008-06-06 13:06 6113原文地址: http://blog.sp ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(三)
2008-05-01 13:53 8838文本继续和大家分享EJB3.1特性,今天谈到的EJB Lite ... -
【翻译】Wicket启示录——理论与实践(三)完
2008-04-11 01:09 6278接下来,我们再看看EditContact类,把新建联系人的话和 ... -
【翻译】Wicket启示录——理论与实践(二)
2008-04-09 23:47 5886第二部分 实践 Application(应用程序) 与 ... -
【翻译】Wicket启示录——理论与实践(一)
2008-04-09 23:15 6807序 Wicket,当多数人看到它时,也许又是带着惯性思考 “j ...
相关推荐
1. 利用注解、反射和工厂模式设计一个简单的IoC容器 2. 该IoC容器包含3个注解和一个IoC容器类(AnnotationConfigApplicationContext),其定义如下: 注解 含义 @Component 标注Bean @Autowired 标注需要被注入的...
1. **简单工厂模式**(simpleFactory):这种模式中,我们通常定义一个工厂类,它根据传入的参数来决定创建哪种具体的产品对象。简单工厂模式适用于产品种类不多,且不会频繁扩展的情况。在测试中,我们可以模拟不同...
工厂模式的IoC应用,特别是在Spring框架中,是一个强大的工具,可以显著提高代码的可维护性和可测试性。`BeanFactory`作为Spring的核心组件,负责bean的创建、依赖注入、生命周期管理和作用域控制,使得开发人员能够...
以下是一个简单的抽象工厂模式在ASP.NET中的应用示例: ```csharp // 定义抽象工厂接口 public interface IPageFactory { Page CreateWebFormPage(); View CreateMvcView(); } // 具体工厂实现,针对ASP.NET Web...
本项目"手写一个SpringIoc容器"旨在模仿Spring的IOC(Inversion of Control,控制反转)功能,帮助开发者深入理解Spring的工作原理,提升对依赖注入(Dependency Injection)模式的认识。 在实现自定义的Spring IOC...
工厂模式通过一个公共的工厂类来创建不同类型的产品,可以根据需求动态地切换产品实现。例如,客户端代码只依赖于工厂接口,而不知道实际创建的对象类型。工厂模式的实现方式多样,包括简单工厂、抽象工厂和工厂方法...
在这个“IOC模式 c#经典例子”中,我们可以看到如何使用Unity,一个流行的.NET框架,来实现依赖注入。 Unity是Microsoft提供的一个轻量级的DI容器,它可以帮助开发者管理对象的生命周期,并在运行时将依赖关系注入...
在IT行业中,框架是软件开发中的重要组成部分,它们提供了一种结构化的方式来组织代码,使得开发者可以更加高效...动手做框架是一个挑战,但这个过程将极大地丰富你的技术视野,帮助你在未来项目中更好地运用这些技术。
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。这种模式适用于当需要创建的对象是一系列相互依赖的对象族,且这些对象的类都处于不同的抽象层次时。在Java中,抽象工厂通常...
DAO(Data Access Object)抽象工厂是一种设计模式,它在软件工程中用于创建DAO对象的类工厂。DAO模式的主要目的是为了封装对数据源的访问,使得业务逻辑层与数据存储层解耦,提高代码的可测试性和可维护性。在Java...
【标题】"自己动手实现IOC和MVC源码"揭示了本文的核心内容,即通过实践来理解并构建IoC(Inversion of Control)和MVC(Model-View-Controller)这两种重要的软件设计模式的源代码。这两者是现代Java Web开发中...
spring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demo...
springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC...
Java Spring代理模式AOP-IOC分析 一、代理模式概述 在软件设计中,代理模式是一种常用的设计模式。...本文对Java Spring代理模式AOP-IOC进行了分析和讨论,并提供了一个示例项目来演示如何使用Spring实现AOP和IOC。
在本主题中,我们将深入探讨如何手写一个基于XML的Spring IOC实现,模仿Spring框架中的`ClassPathXmlApplicationContext`。这个实现旨在帮助理解Spring底层的工作原理,并加深对IoC容器的理解。 首先,我们需要创建...
在它们的背后有着同一个模式,这个模式决定了这些容器进行组 件装配的方式。人们用一个大而化之的名字来称呼这个模式:“控制反转”( Inversion of Control,IoC)。在本文中,我将深入探索这个模式的工作原理,给...
这个"手写Spring IOC注解实现版本"项目旨在帮助我们深入理解Spring框架的工作原理,通过实际动手实现来增强对IoC容器和注解驱动编程的理解。 在Spring中,IOC意味着应用程序不再直接创建对象,而是将对象的创建和...
标题 "手动实现一个IOC容器.zip" 提到的主题是关于如何从零开始构建自己的依赖注入(Dependency Injection,简称DI)容器,这在Java开发中尤为重要,特别是对于Spring框架的理解和学习。IOC容器是Spring的核心功能之...
IoC设计模式的实现通常依赖于容器,如Spring框架在Java中就是一个著名的IoC容器。开发者可以通过XML配置、注解或者编程式的方式来定义对象及其依赖关系。例如,在Spring中,我们可以在XML配置文件中定义Bean(代表一...
通过自己动手实现,初学者可以更好地理解Spring是如何在幕后管理对象和处理依赖的,这对于提升编程技能和设计模式的理解非常有益。同时,这也是软件开发中常用的一种学习方法——通过模仿和实践来深入理解复杂的概念...