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

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

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

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-11-04 09:14:05

创建对象与使用对象——谈谈工厂的作用的相关文章

谈谈工厂的作用

[转载]创建对象与使用对象——谈谈工厂的作用 在设计模式的教学和推广过程中,很多企业学员和在校学生经常问我,工厂模式(包括简单工厂模式.工厂方法模式和抽象工厂模式)到底有什么用,很多时候通过反射机制就可以很灵活地创建对象,为毛还要工厂?,在本文中我将围绕创建对象和使用对象来简单谈谈工厂的作用. 与一个对象相关的职责通常有三类:对象本身所具有的职责.创建对象的职责和使用对象的职责.对象本身的职责比较容易理解,就是对象自身所具有的一些数据和行为,可通过一些公开的方法来实现它的职责.在本文中,我们将简

7中创建对象的方式(工厂模式、构造函数模式、原型模式、动态原型模式等分析)

1.工厂模式 // 定义工厂函数 function createPerson(name, age, hobby) { // 创建一个临时object对象 var obj = new Object(); // 将工厂函数的参数赋值给临时对象 obj.name = name; obj.age = age; obj.hobby = hobby; obj.sayName = function() { console.log("我的名字叫:"+this.name); } // 返回这个包装好的临

谈谈SDRAM的作用

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

Javascript之创建对象(工厂模式与构造函数模式)

虽然Object构造函数或对象字面量都可以创建单个对象,但是这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复的代码.为了解决这个问题,就可以使用工厂模式来创建对象. 1.工厂模式 在ECMAScript中是无法创建类的,开发人员就发明了一种函数,用函数来封装特定接口创建对象的细节. function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = j

Javascript我学之六对象工厂函数与构造函数

本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript还提供了其他方法创建对象. 1).使用工厂函数创建对象 我们可以编写一个函数,此函数的功能就是创建对象,可将其称为“对象工厂方法”. 1 //工厂函数 2 function createPerson(name, age, job) { 3 var o = new Object(); 4 o.name

简单工厂模式 - 学习笔记

工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式可以分为三类: 简单工厂模式(Simple Factory) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 这三种模式从上到下逐步抽象,并且更具一般性. 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口.工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类

创建对象与对象依赖关系

创建对象 SpringIOC容器,是spring核心内容.作用: 创建对象 & 处理对象的依赖关系 IOC容器创建对象: 创建对象, 有几种方式: 1) 调用无参数构造器 在bean类中写入无参构造函数 public User() { // TODO Auto-generated constructor stub } xml配置文件 <!-- 1.默认无参的构造器 --> <bean id="user1" class="com.gqx.create.

设计模式整理_工厂模式

一.简单工厂模式. 通常情况下,在代码中需要创建一系列对象的时候,如果需要创建新的同类型的对象,就需要对原代码进行修改,此时就不符合对修改关闭的原则,因此,我们将创建对象于使用对象的代码分隔开来,在工厂类中创建工厂,然后如果需要新的对象,只需要修改工厂的类即可. public interface Car /*在这里定义需要生成的实例,针对抽象组件*/{ public void run(); } class BenzCar /*实例*/ implements Car { @Override pub

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

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