设计模式之工厂模式


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


下面引用一个网友的例子来说明一下具体实现过程:现在要完成一个计算器的功能,要求输入两个数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{

	@Override
	public double getResult(double A, double B) {
		return A+B;
	}	
}
/**
 * @author 
 * @date
 * @function 减法产品类
 */
public class SubProduct implements Product{

	@Override
	public 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 stub
		Product 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{

	@Override
	public Product createOperate() {
		
		return new SubProduct();
	}	
}
/**
 * @author 
 * @date
 * @function 减法工厂
 */
public class AddFactory implements Factory{
	@Override
	public Product createOperate() {
		
		return new AddProduct();
	}
}
客户端代码:

/**
 * @author 
 * @date
 * @function 客户端代码
 */
public class Client_1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Factory fac=new AddFactory();
		Product pro=fac.createOperate();
		double res=pro.getResult(2, 1);
		System.out.println(res);	
	}
}

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

3.两者对比

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

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

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值