谈谈工厂的作用

【转载】创建对象与使用对象——谈谈工厂的作用

在设计模式的教学和推广过程中,很多企业学员和在校学生经常问我,工厂模式(包括简单工厂模式、工厂方法模式和抽象工厂模式)到底有什么用,很多时候通过反射机制就可以很灵活地创建对象,为毛还要工厂?,在本文中我将围绕创建对象和使用对象来简单谈谈工厂的作用。

与一个对象相关的职责通常有三类:对象本身所具有的职责、创建对象的职责和使用对象的职责。对象本身的职责比较容易理解,就是对象自身所具有的一些数据和行为,可通过一些公开的方法来实现它的职责。在本文中,我们将简单讨论一下对象的创建职责和使用职责。

在Java语言中,我们通常有以下几种创建对象的方式:

(1) 使用new关键字直接创建对象;

(2) 通过反射机制创建对象;

(3) 通过clone()方法创建对象;

(4) 通过工厂类创建对象。

毫无疑问,在客户端代码中直接使用new关键字是最简单的一种创建对象的方式,但是它的灵活性较差,下面通过一个简单的示例来加以说明:

[java] view plain copy

  1. class LoginAction {
  2. private UserDAO udao;
  3. public LoginAction() {
  4. udao = new JDBCUserDAO(); //创建对象
  5. }
  6. public void execute() {
  7. //其他代码
  8. udao.findUserById(); //使用对象
  9. //其他代码
  10. }
  11. }

在LoginAction类中定义了一个UserDAO类型的对象udao,在LoginAction的构造函数中创建了JDBCUserDAO类型的udao对象,并在execute()方法中调用了udao对象的findUserById()方法,这段代码看上去并没有什么问题。下面我们来分析一下LoginAction和UserDAO之间的关系,LoginAction类负责创建了一个UserDAO子类的对象并使用UserDAO的方法来完成相应的业务处理,也就是说LoginAction即负责udao的创建又负责udao的使用,创建对象和使用对象的职责耦合在一起,这样的设计会导致一个很严重的问题:如果在LoginAction中希望能够使用UserDAO的另一个子类如HibernateUserDAO类型的对象,必须修改LoginAction类的源代码,违反了“开闭原则”。如何解决该问题?

最常用的一种解决方法是将udao对象的创建职责从LoginAction类中移除,在LoginAction类之外创建对象,那么谁来负责创建UserDAO对象呢?答案是:工厂类。通过引入工厂类,客户类(如LoginAction)不涉及对象的创建,对象的创建者也不会涉及对象的使用。引入工厂类UserDAOFactory之后的结构如图1所示:

图1 引入工厂类之后的结构图

工厂类的引入将降低因为产品或工厂类改变所造成的维护工作量。如果UserDAO的某个子类的构造函数发生改变或者要需要添加或移除不同的子类,只要维护UserDAOFactory的代码,而不会影响到LoginAction;如果UserDAO的接口发生改变,例如添加、移除方法或改变方法名,只需要修改LoginAction,不会给UserDAOFactory带来任何影响。

在所有的工厂模式中,我们都强调一点:两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有。将对象的创建和使用分离,也使得系统更加符合“单一职责原则”,有利于对功能的复用和系统的维护。

此外,将对象的创建和使用分离还有一个好处:防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中,这在Joshua Kerievsky的《重构与模式》一书中有专门的一节来进行介绍。因为有时候我们创建一个对象不只是简单调用其构造函数,还需要设置一些参数,可能还需要配置环境,如果将这些代码散落在每一个创建对象的客户类中,势必会出现代码重复、创建蔓延的问题,而这些客户类其实无须承担对象的创建工作,它们只需使用已创建好的对象就可以了。此时,可以引入工厂类来封装对象的创建逻辑和客户代码的实例化/配置选项。

使用工厂类还有一个“不是特别明显的”优点,一个类可能拥有多个构造函数,而在Java、C#等语言中构造函数名字都与类名相同,客户端只能通过传入不同的参数来调用不同的构造函数创建对象,从构造函数和参数列表中也许大家根本不了解不同构造函数所构造的产品的差异。但如果将对象的创建过程封装在工厂类中,我们可以提供一系列名字完全不同的工厂方法,每一个工厂方法对应一个构造函数,客户端可以以一种更加可读、易懂的方式来创建对象,而且,从一组工厂方法中选择一个意义明确的工厂方法,比从一组名称相同参数不同的构造函数中选择一个构造函数要方便很多。如图2所示:

在图2中,矩形工厂类RectangleFactory提供了两个工厂方法createRectangle()和createSquare(),一个用于创建长方形,一个用于创建正方形,这两个方法比直接通过构造函数来创建长方形或正方形对象意义更加明确,也在一定程度上降低了客户端调用时出错的概率。

那么,有人可能会问,是否需要为设计中的每一个类都配备一个工厂类?答案是:具体情况具体分析。如果产品类很简单,而且不存在太多变数,其构造过程也很简单,此时无须为其提供工厂类,直接在使用之前实例化即可,例如Java语言中的String类,我们就无须为它专门提供一个StringFactory,这样做反而有点像杀鸡用牛刀,大材小用,而且会导致工厂泛滥,增加系统的复杂度。

时间: 2024-10-23 11:34:32

谈谈工厂的作用的相关文章

创建对象与使用对象——谈谈工厂的作用

工厂模式(包括简单工厂模式.工厂方法模式和抽象工厂模式)到底有什么用,很多时候通过反射机制就可以很灵活地创建对象,为毛还要工厂?,在本文中我将围绕创建对象和使用对象来简单谈谈工厂的作用. 与一个对象相关的职责通常有三类:对象本身所具有的职责.创建对象的职责和使用对象的职责.对象本身的职责比较容易理解,就是对象自身所具有的一些数据和行为,可通过一些公开的方法来实现它的职责.在本文中,我们将简单讨论一下对象的创建职责和使用职责. 在Java语言中,我们通常有以下几种创建对象的方式: (1) 使用ne

谈谈SDRAM的作用

SDRAM这个至今还在用的存储器,虽然被后来的DDR取代,掌握好它还是很重要的.之前在调试时,确实费了好大劲,它的复杂性毋庸置疑,一般人要想弄懂他,得花1个月左右吧,至少我这么认为.话说回来,SDRAM的作用是什么呢?答案肯定是存储,如果你没在项目中运用它的话,是很难体会到它的作用的,最近在弄SDRAM的VGA显示,其实调好后,也没那么神奇.先以高频率100M往SDRAM写数据,之后读出数据时,因为VGA时钟频率为25M,肯定不能直接给VGA,需要把SDRAM读出的数据缓存在DCFIFO中,通过

简单工厂模式,工厂方法模式,抽象工厂模式

简单工厂模式.抽象工厂模式.工厂方法模式,这三种工厂模式都属于设计模式中的创建型模式,它们在形式和特点上也多少有些相似,其最终目的都是帮我们将对象的实例化部分取出来,进而优化系统架构,增强系统的扩展性,也就是说更好的体现开放封闭原则. 简单工厂模式: 概念: 简单工厂模式是类的创建模式,又叫做静态工厂方法模式,是由一个工厂类根据传入的参量决定创建出哪一种产品类的实例,涉及到工厂角色.抽象产品角色以及具体产品角色. 结构图: 分析: 一: 简单工厂类是整个模式的关键所在,包含了必要的逻辑判断,根据

静态工厂

2.Factory(静态工厂)作用:(1)代替构造函数创建对象(2)方法名比构造函数清晰JDK中体现:(1)Integer.valueOf(2)Class.forName类图: //静态工厂模式 public class StaticFactory { public static Object createModel() { return new Object(); } }

设计模式(一)简单工厂 PHP(Simple Factory For PHP)

最近天气变化无常,身为程序猿的寡人!~终究难耐天气的挑战,病倒了,果然,程序猿还需多保养自己的身体,有句话这么说:一生只有两件事能报复你:不够努力的辜负和过度消耗身体的后患. 设计模式--简单工厂 (Simple Factory)又称静态工厂方法模式(Static Factory Method Pattern) 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类.简单工厂实例化的类具有相同的接口或者基类,在子类比较固定并不需要扩展时,可以使用简单工厂,一定程度上可以很好的降低

设计模式- 简单工厂模式、工厂方法模式及其比较

简单工厂模式及实例 前言工大有许多同学是做java的,大家都知道java最大的优点是它的完全OO化和它在多年的发展过程中吸收和总结了许多先进的框架与模式,其中工厂模式就是最常用的模式之一.下面我想将我在学习和实践过程中对工厂模式的认识与了解介绍给大家.由于笔者能力限制,在实践中也没参与过什么大的项目,笔者参与过的项目用到的工厂模式主要是简单工厂模式(Simple Factory)和工厂方法模式(Factory Method),所以笔者在本文主要介绍的是这两种模式.准备知识在OO设计领域,我们知道

设计模式~简单工厂模式(Factory)

简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类.简单工厂实例化的类具有相同的接口或者基类,在子类比较固定并不需要扩展时,可以使用简单工厂.如数据库生产工厂就是简单工厂的一个应用.         采用简单工厂的优点是可以使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性:缺点是可实例化的类型在编译期间已经被确定,如果增加新类 型,

OC基础(八)类工厂方法

一:基本用法 类工厂方法作用:提高编码效率,快速创建对象的方法 规范:1.一定是+开头   2.方法以类名开头,首字母小写. 3.一定有返回值,返回类型为id/instancetype 比如:在类的声明和实现中 无参数: + (instancetype)person; + (instancetype)person{ return [[Person alloc] init]; } 在主函数创建对象中就可以直接使用,简化代码. Person *p1 = [Person person];  //此处的

工厂模式理解

所谓工厂模式,工厂即指生产物品的车间,代码的工厂模式,就是提供实例方法,把他封装起来,就成为了一个工厂,而工厂就可以为我们提供实例对象,另外工厂还有一个特性,就是我们不用关心工厂是如何生产实例的,我们只需要告诉它要生产什么实例,它就为我们提供什么实例 而抽象工厂,作用是为了更大可能的解除方法调用间的耦合度,举例为在.net中我们通常会使用到三层,我们直接用bll去掉dal里的方法,两者直接就会存在很大的耦合,借于此,我们会用借口去完成之间的联系,为dal编写一个接口,然后继承.在bll调用dal