工厂方法模式 VS 简单工厂模式

来源:互联网 发布:淘宝实体店加盟条件 编辑:程序博客网 时间:2024/05/16 04:08

这片博客我将以一个计算器的例子跟大家分享一下我对简单工厂模式和工厂方法模式的理解。

计算器中的基本运算有 加、减、乘、除四个。

首先定义一个运算类,类中有numA和numB这两个需要运算的变量,有一个getResult方法用于获取运算结果。

public class Operation{

private double numA;

private double numB;

public double getResult(){}

}

其次,定义加、减、乘、除四个实现类分别继承运算类Operation,并重写Operation中的getResult方法。

public class OperationAdd extends Operation {

public double getResult(){

double result = 0;

result = numA + numB;

return result;

}

public class OperationSub extends Operation {

public double getResult(){

double result = 0;

result = numA - numB;

return result;

}

public class OperationMul extends Operation {

public double getResult(){

double result = 0;

result = numA * numB;

return result;

}

public class OperationDiv extends Operation {

public double getResult(){

double result = 0;

if (numB == 0)

throw new Exception("除数不能为0”);

result = numA / numB;

return result;

}

简单工厂模式的实现方式:

需要定义一个简单工厂类OperationFactory,在工厂类中进行switch分支的判断。

class OperationFactory{

public static Operation createOperate(String operate) 

{

operation oper = null;

switch(operate)

{

case "+":

oper = new OperationAdd();

break;

case "-":

oper = new OperationSub();

break;

case "*":

oper = new OperationMul();

break;

case "/":

oper = new OperationDiv();

break;

}

return oper;

}

}

客户端调用如下:

Operation oper = OperationFactory.createOperate("+");

oper.numA = 1;

oper.numB = 2;

double result = opper.getResult();

到这里,简单工厂模式就完成了,看起来是不是很清晰,很好用,感觉把该封装的都封装了?那么问题来了,现在万变的客户提了一个需求:“麻烦给我加一个开根运算”。然后你要怎么做?你能做的就是添加一个开根的class,然后在简单工厂类OperationFactory的switch中加一条分支。添加开根的运算类没有什么问题,但是在简单工厂类OperationFactory的switch中加一条分支是不是看起来怪怪的?是的,它违背了上一篇博客分享中的一条原则-开闭原则。开闭原则的原理就是对扩展开放,对修改关闭,而此时,修改了工厂类,就是对修改开放了,因此就不符合开闭原则。开闭原则这个裁判吧简单工厂模式给pass掉了。所以严格来说,简单工厂模式并不能算23种设计模式中的一种。

简单工厂方法被pass掉了,那么一定就会有一个新的方法取代他,这个方法就是伟大的工厂方法模式。我们试着用工厂方法模式再一次对加减乘除运算进行编码。

工厂方法模式的实现方式:

前面的operation运算类和加、减、乘、除这四个实现类依然不动。我们创建一个工厂接口。

interface IFactory

{

operation CreateOperation();

}

然后分别创建加、减、乘、除四个工厂类实现上面的工厂接口。

class AddFactory implements IFactory{

public Operation createOperation(){

return new OperationAdd();

}

}

class SubFactory implements IFactory{

public Operation createOperation(){

return new OperationSub();

}

}

class MulFactory implements IFactory{

public Operation createOperation(){

return new OperationMul();

}

}

class DivFactory implements IFactory{

public Operation createOperation(){

return new OperationDiv();

}

}

客户端调用代码:

IFactory operFactory = new AddFactory();

Operation oper = operFactory.createOperation();

oper.numA = 1;

oper.numB = 2;

double result = oper.getResult();

到这里,工厂方法类也跟大家分享完了。现在万变的客户再让你增加一个开根的运算,你需要做的是添加一个开根的实现类,然后再增加一个开根的工厂类继承IFactory工厂接口并实现开根的类。然后通过客户端调用开根运算即可。这样只是增加了类,而不会对原有类进行修改。避免之前好用的代码被修改发生新的bug。满足了开闭原则。是不是很happy?

最后,还有一个答疑解惑的过程差点遗漏,可能有的小盆宇会问,工厂方法模式,在工厂类中实现了加减乘除的运算类,然后调用工厂类,那么我们为什么不可以直接调用加减乘除的运算类呢?

这个问题其实刚开始我也困惑了一段时间,不过后来在项目开发中我理解了。设计模式举例一般都会举一些比较简单的、逻辑不是很复杂的例子,因为毕竟设计模式的本意是让你掌握编程的一种思维,而不是给你普及java的基础知识。所以举例的加减乘除计算器运算的逻辑很简单。但是真正到了项目中,就不是这种简单的加减乘除了,也许一个类的实现需要准备很多的参数,准备参数的过程需要一些代码逻辑做支撑。那时候工厂类其实就是对一个类的实例化做了封装,让客户端直接调用工厂类,而不必追究工厂类中到底是如何实例化一个对象的。这其实也是面向对象中的一个特性:封装。不知道我这么说小伙伴们会不会理解,欢迎留言。看到必定回复!