2.2.    工厂模式

基于手工构建组件的诸多弱点,1995年“大师4人组”(GoF)在其经典著作《DesignPatterns》一书中提出了“工厂模式”,这种模式在一定程度上有效的解决了之前所遇到的问题,时至今日仍然被大量应用于软件工程的设计当中。

我们先来看之前的例子,首先来创建一个银行工厂和一个存折工厂,用于创建这两个依赖对象。

public class BankFactory {

public Bank createBankICBC() {

return new BankICBC("Tianjin", 100);

}

}

 

public class DepositBookFactory {

public DepositBook createDepositICBC() {

return new DepositBookICBC("62202", "current", "CNY");

}

}

有了这两个能够创建依赖对象的工厂,我们就可以在储户类Depositor中利用它们方便的构建出银行和存折这两个依赖。

public class Depositor {

private Bank bank;

private DepositBook depositBook;

public Cash withDraw(BigDecimal amount) {

bank = new
BankFactory().createBankICBC(); // 工厂创建依赖

depositBook = new
DepositBookFactory().createDepositICBC();// 工厂创建依赖

return bank.withDraw(depositBook,
amount);

}

}

我们可以看到,用工厂创建依赖对象,可以将创建对象的过程隐蔽,Depositor类的开发者利用这种透明创建对象的方式则可避免手工构建复杂依赖关系图所带来的诸多不便。并且,当依赖的构造方法接口发生变更时,影响到的也只是工厂类,而不会影响到调用工厂类的依赖者类本身,从而降低了系统的维护成本。

在实际的开发中,工厂往往是被定义为静态的单例模式的,即在一个JVM中有且仅有一个工厂的实例。但由于静态单例模式有很多的缺陷,因此在依赖注入框架流行之后这种模式已经渐渐的被抑制使用了。

但是随着软件工程的不断复杂化和规模化,工厂模式同样的遇到了很多问题而被开发人员诟病。围绕着这个话题的讨论有很多,我们不再一一列举,只举一个比较常见的问题来说明一下。

假设我们的银行不只有工商银行,还有招商银行、中国银行等等,这样就需要我们维护一个越来越庞大的工厂类。之前的Bank工厂就要逐渐这样增加create方法:

public class BankFactory {

public Bank createBankICBC() {

return new BankICBC("Tianjin", 100);

}

public Bank createBankCMB() { // …… };

public Bank createBankBOC() { // …… };

// ……

}

这样工厂类自身的维护成本逐渐增大,就成为了工厂模式的一个很大的障碍。因此很多开发者想办法用参数化的形式,来减少工厂类的维护量。

public class BankFactory {

public Bank createBank(BankVender bankVendor)
{ // 参数化的工厂方法

switch (bankVendor) {

case ICBC:

return createBankICBC();

case CMB:

return createBankCMB();

default:

return createBankICBC();

}

}

// ……

}

但是这样一来又会回到手工new对象的一个问题,即如果工厂方法的参数发生了变化,可能会引起全部调用到该工厂方法的代码都需要修改及做相应的回归测试。

2.3.    ServiceLocator模式

基于上面工厂模式的诸多问题,一些聪明的开发者提出了改进版的工厂模式:ServiceLocator,即服务定位器。这种模式的核心思想是,将构建依赖的接口彻底与依赖者分离,并将此依赖作为“服务”绑定到一个标识符(通常是一个字符串),而后依赖者则可通过这个标识符获取被绑定的依赖。例如我们的例子中,可以这样获得Bank和DepositBook的依赖:

public class Depositor {

private Bank bank;

private DepositBook depositBook;

public Cash withDraw(BigDecimal amount) {

bank = (Bank) new
ServiceLocator().get("BankICBC");

depositBook = (DepositBook) new
ServiceLocator().get("DepositBookICBC");

// 从ServiceLocator容器中获取依赖对象

return bank.withDraw(depositBook,
amount);

}

}

此处ServiceLocator#get(String)这个API的String型参数即为“服务”的标识符。那么这个标识符是如何被绑定到依赖的对象上的呢?答案是开发者需要实现一个能够管理这些依赖(即“服务”)的、类似于工厂类的一个单独的类,这也常常被称作“ServiceLocator容器”,这个容器负责各种依赖的注册、标识符绑定、提供依赖对象等工作。

说到此处大家一定会觉得开发这样一个ServiceLocator容器花的代价一定不小。不错,正因为如此,JCP组织联合各IT供应商制订了统一的ServiceLocator容器标准,开发者可以只管开发自己的依赖类,然后IT供应商提供的ServiceLocator容器实现(即各种应用服务器级中间件)通过统一的命名规则将某个标识符绑定到这些依赖类并注册到容器中,等待开发者的请求命令。

而ServiceLocator模式作为业界标准统一化后,一个最典型的应用便诞生了:JNDI。直到今天JNDI都是组件、包括分布式组件开发中不可或缺的耦合方式。例如DataSource资源的获取、RemoteEJB对象的获取等等,都是通过JNDI查找的方式进行的。例如获取RemoteEJB的时候,我们可以执行这样的JNDI查找:

RemoteBean rb = (RemoteBean)
initialContext.lookup("java:comp/env/TEST/RemoteBeanImpl");

但是ServiceLocator模式最大的弱点就是,依赖对象的获取强依赖于ServiceLocator容器,除非开发者愿意花费大量成本自己实现ServiceLocator容器,否则就必须要中间件提供商的支持,这就给我们的开发和测试带来了很大困扰。拿JNDI容器的实现来说,各提供商,比如Tomcat、JBoss、WebLogic、WebSphere等,对于JNDI的统一命名标识符的规则就不尽相同,使得开发者往往必须通过各自应用服务器的控制台才能准确找到需要的JNDI名,并且在单元测试时如果没有应用服务器启动下的环境,单元测试是难以顺利进行的,给维护带来了不小的困扰。

依赖注入及AOP简述(二)——工厂和ServiceLocator .的更多相关文章

  1. 依赖注入及AOP简述(十二)——依赖注入对象的行为增强(AOP) .

    四.依赖注入对象的行为增强(AOP) 前面讲到,依赖注入框架的最鲜明的特点就是能够提供受容器管理的依赖对象,并且可以对对象提供行为增强(AOP)功能,所以这一章我们来讨论有关AOP的话题. 1.    ...

  2. 依赖注入及AOP简述(五)——依赖注入的方式 .

    二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1.     依赖注入的方 ...

  3. 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .

    3.2.    “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模 ...

  4. 依赖注入及AOP简述(三)——依赖注入的原理

    3.     “依赖注入”登场 于是诸多优秀的IT工程师开始想出了更加轻量便利.更加具有可测试性和可维护性的设计模式——IoC模式.IoC,即Inversion of Control的缩写,中文里被称 ...

  5. 依赖注入及AOP简述(十三)——AOP应用举例(完结) .

    2.     AOP应用举例 在一般的应用程序开发中,有一些典型的AOP应用,使得开发者可以专注于业务逻辑本身,而不是与之完全无关的一些“方面”. l        首先就是关于前面介绍过的日志输出类 ...

  6. 依赖注入及AOP简述(九)——单例和无状态Scope .

    三.依赖注入对象的Scope及其生命周期 在前面的章节我们讲到,依赖注入容器之所以能够区别于以往的ServiceLocator等容器,是在于其不但能够自动构建多层次的.完整的依赖关系图,并且可以管理依 ...

  7. 依赖注入及AOP简述(七)——FQCN请求模式

    2.2.    FQCN请求模式 为了弥补纯字符串请求模式中的类型安全问题,全类名(FQCN)请求模式就应运而生了.其思想便是,在向容器请求依赖对象的时候,不是通过字符串的标识符.而是通过被请求的依赖 ...

  8. 依赖注入及AOP简述(六)——字符串请求模式 .

    2.     依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...

  9. 依赖注入及AOP简述(一)——“依赖”的概念 .

    一.入门:依赖注入 作为一种全新的设计模式理念,“依赖注入”这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的“依赖注入框架”,也越来越多的被当作软件工程开发过程中使用的基础框架. ...

随机推荐

  1. telnet查看memcached运行参数说明

    在Linux/Windows系统中启动memcached的命令请查看http://weilingfeng98.iteye.com/admin/blogs/1741179 启动完memcached服务器 ...

  2. 几种基于javaI/O的文件拷贝操作比较

    最近公司的项目用到文件拷贝,由于涉及到的大量大文件的拷贝工作,代码性能问题显得尤为重要,所以写了以下例子对几种文件拷贝操作做一比较: 0.文件拷贝测试方法 public static void fil ...

  3. ubuntu桌面环境配置及切换

    修改ubuntu默认启动的桌面环境:Ubuntu是否启动图形化界面取决于default-display-manager的设置. vi /etc/X11/default-display-manager值 ...

  4. jquery .net 无刷新多文件上传

    Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中的使用,您也可以点击下面的链接进行演示 ...

  5. AppSettings

    1.winform中读写配置文件appSettings 一节中的配置. #region 读写配置文件 /// <summary> /// 修改配置文件中某项的值 /// </summ ...

  6. MySql优化-你的SQL命中索引了吗

    在项目开发中SQL是必不可少的,表索也一样.这些SQL的运行性能不知道吗?有多少是命中了索引的?命中哪个索引?索引中有哪个是无效索引?这些无效索引是否会影响系统的性能?带着这些问题我们一起来学习一下. ...

  7. C#之回到了最初的起点----解决方案、项目、程序集、命名空间

    C#之回到了最初的起点----解决方案.项目.程序集.命名空间 ——Percy 初学者很容易把这些概念搞混淆.先说说项目(Project),通俗的说,一个项目可以就是你开发的一个软件.在.Net下,一 ...

  8. 时间的获取和转换,C#和Sql

    我们可以通过使用DataTime这个类来获取当前的时间.通过调用类中的各种方法我们可以获取不同的时间:如:日期(2008-09-04).时间(12:12:12).日期+时间(2008-09-04 12 ...

  9. OA、CRM、ERP之间的区别和联系是什么?

    我们假设你是某机械行业的销售,一切从今天你收到公司的邮件,去上海参加展会开始 因为 去展会 所有 首先 你打开 OA 登陆 填写出差申请表 送交主管审批 填表--审批--行政订票酒店 然后呢 你飞去上 ...

  10. 注册宝第五期beta2插件模块下载及说明

    原文:http://bbs.84zcb.com/showtopic-1882.aspx [软件名称]:注册宝插件模块 [软件版本]:V1.4 [软件大小]:6.36M [软件语言]:简体中文 [授权方 ...