设计模式之工厂模式

来源:互联网 发布:jmeter数据库查询结果 编辑:程序博客网 时间:2024/06/14 19:36


参考资料:《大话设计模式》


下面引用一个网友的例子来说明一下具体实现过程:现在要完成一个计算器的功能,要求输入两个数A,B和一个运算符号(+,-,*,%),能够输出运算结果。注意哦,我们这里说的是面向对象的编程,别总想面向过程的思路。既然是面向对象,那首先我们想想要有哪些类吧!先想一想,可不可以这样有一个类Product里面包含add,sub,mult,div四个方法,然后再包含两个成员变量A和B呢?通过这个类是可以完成目前的要求,可以要是从软件工程的角度,需求变化在软件开发过程中是无法避免的,那么现在又要完成取余(%)操作呢?这是要修改Product类了吧,这就违背面向对象设计模式的OCP原则了。这显然不是一个好的设计。实际上这是一个典型的利用“简单工厂模式”的例子,那看看利用简单工厂模式怎么做吧。首先声明一个Product类,类中包含getResult方法,然后声明四个类AddProduct,SubProduct,MultProduct,DivProduct四个类继承Product类,四个子类中重写getResult方法,分别完成加,减,乘,除操作。现在要说工厂了,工厂实际上也是一个类Factory,类中包括一个Product类型成变量和CreateOperator()方法,该类用于创建各种Product实例,可以根据传递的参数动态创建AddProduct,SubProduct,MultProduct,DivProduct各种实例。这时如果要增加取余(%)操作,只需要建一个取余操作的子类,然后再工厂类中增加一点点创建的代码就KO了。这样的话,客户端只需要实例化一个工厂类就可以创建各种Product对象了。


1.简单工厂模式

首先给出简单工厂模式的url图:

它由三种角色组成(关系见下面的类图):
1、工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。

2、抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

3、具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。


在对应具体设计计算器这个例子,URL如下(我的代码跟url图有点不同,在代码中,运算类我定义成了抽象接口的形式,然后参数A和B是作为参数传入GetResult()方法):


/** * @author  * @date * @function 抽象产品接口 */public interface Product {public double getResult(double A, double B);}
/** * @author  * @date * @function 加法产品类 */public class AddProduct implements Product{@Overridepublic double getResult(double A, double B) {return A+B;}}
/** * @author  * @date * @function 减法产品类 */public class SubProduct implements Product{@Overridepublic double getResult(double A, double B) {return A-B;}}
/** * @author  * @date * @function 简单工厂类 */public class SimpleFactory {public static Product createOperate(String operate){ //这里定义为静态方法,方法后便类可以直接调用Product pro=null;if(operate.equals("+"))pro= new AddProduct();else if(operate.equals("-"))pro= new SubProduct();return pro;}}

客户端代码:

/** * @author  * @date * @function 客户端代码 */public class Client {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubProduct pro=SimpleFactory.createOperate("+");double result=pro.getResult(2,1);System.out.println(result);}}

 接下来,假如我们要增加一个取余操作,那么我们需要增加一个具体产品类,即ModProduct类,该类继承Product类,重写 getResult()方法即可。可见,该产品类符合开闭原则——对扩展开放、对修改关闭;再来看看工厂类,因为上面只有一个简单的工厂类,当增加一个产品后,就需要在工厂类中进行逻辑判断,不符合开闭原则。

既然这个工厂类与分支耦合,那么我们就对它下手,根据依赖倒转原则,把工厂类抽象出一个接口,该接口只有一个方法,就是创建抽象产品的工厂方法。然后,所有的要生成具体类的工厂,就去实现这个接口,这样,一个简单工厂模式的工厂 类,变成了一个工厂抽象接口和多个具体生成对象的工厂,于是工厂方法模式就诞生了。

2.工厂方法模式


该例子的URL图:


代码如下:

产品类不做任何改变

/** * @author  * @date * @function 抽象工厂接口 */public interface Factory {public Product createOperate();}
/** * @author  * @date * @function 加法工厂 */public class SubFactory implements Factory{@Overridepublic Product createOperate() {return new SubProduct();}}
/** * @author  * @date * @function 减法工厂 */public class AddFactory implements Factory{@Overridepublic Product createOperate() {return new AddProduct();}}
客户端代码:

/** * @author  * @date * @function 客户端代码 */public class Client_1 {public static void main(String[] args) {// TODO Auto-generated method stubFactory fac=new AddFactory();Product pro=fac.createOperate();double res=pro.getResult(2, 1);System.out.println(res);}}

再来分析,当我们需要增加一个取余操作时,需要同时增加一个具体产品类和具体工厂类,ModProduct类和ModFactory类,不需要改动工厂类的代码,只需要改动客户端代码。符合开闭原则。

3.两者对比

1. 简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是,当增加功能时,需要改变工厂类的逻辑代码,这违背了开放-封闭原则。

2. 工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移动了客户端代码进行。你想要加功能,本来是该工厂类的,而现在是修改客户端。

3.两者都集中封装了对象的创建,降低了客户程序与产品对象的耦合。

4.工厂方法模式是简单工厂模式的进一步抽象和推广,由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量。


原创粉丝点击