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. .NET 基础串讲

    C#基础 .NET介绍 —计算机发展史 第一代语言:机器语言 0101 第二代语言:汇编语言, 用一些简洁的英文字母.符号串来替代一个特定指令的二进制串 第三代语言:接近于数学语言或人的自然语言,同时 ...

  2. HttpApplication事件执行顺序(转)

    HttpApplication 类的实例(Global继承自该类)是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的.HttpApplication 类的一个实例在其生存期内被用于处理多个 ...

  3. ios 75个工具

    如果你去到一位熟练的木匠的工作室,你总是能发现他/她有一堆工具来完成不同的任务.   软件开发同样如此.你可以从软件开发者如何使用工具中看出他水准如何.有经验的开发者精于使用工具.对你目前所使用的工具 ...

  4. php中的短标签 太坑人了

    今天配置了一个php页面去修改svn密码问题,结果调了半天,最后在Windows和 Linux的运行现象是不一样,运行结果更不一样了,关键是完全一模一样的代码. 最后发现是短标签引起的,Windows ...

  5. c++对文件操作的支持(一)

    #include <stdio.h> #include <iostream> #include <fstream> using namespace std; voi ...

  6. mysql用root用户启动后其他用户无法启动不问题

    问题描述:用root账户启动mysql后,在用mysql用户或其他非root账户启动不了mysql问题解决:通过看mysql的err日志,发现 Failed to open log (robert-b ...

  7. WebView高危接口安全检测

    高危]WebView高危接口安全检测共2处详细内容:在Android系统4.3.1~3.0版本,系统webview默认添加了searchBoxJavaBridge_接口,如果未移除该接口可能导致低版本 ...

  8. 简便数据库——ORMLite框架

    一.创建DataBase //使用 Singleton 避免產生多個實例(instance),要注意 thread safe 這邊使用雙重鎖定(Double-checked locking) 使用 T ...

  9. 理解Window和WindowManger

    一.Window简介 作用:桌面上显示一个类似悬浮的东西. 介绍:Window是一个抽象类,实现是由PhoneWindow.WindowManager是外界访问Window的入口.但是最终实现是在Wi ...

  10. 1002 Fire Net

    用递归实现各种情况的枚举,可以看做是考察DPS的简单实现. #include <stdio.h> ][]; int place(int x,int y){ int i; ;i--){ ) ...