一、简单工厂模式
软件设计的目标:可维护、可复用、可扩展、灵活性好!
通过封装、继承、多态把程序的耦合度降低,使程序容易修改,并且易于复用。
以一个简单的计算器程序(加减乘除)为例,实现该程序有多种方式:
- 在main方法里把计算器的逻辑写完;
- 在包含主方法的类里面定义一个方法,将加减乘除的逻辑放到该方法里。main方法调用此方法;
- 重新定义一个计算器类,将加减乘除的方法挪到该类中。main方法调用该类的方法。
1和2中方法的调用者和被调用者高度重合,耦合度非常高。3减低了耦合度,调用者和被调用者分离,但是所有的计算方法拥挤在一个类中,修改程序变得危险。
假如一个新手需要在计算器类中新增一个方法,但是他不小心改动了其他已有的方法,这样就很危险了!
利用继承和多态的特点完善下
定义一个抽象父类 Operation,Operation 类中定义两个成员变量 numberA 和 numberB,以及一个抽象方法 getResult()。
加减乘除分别定义一个单独的类 OperationAdd、OperationSub、OperationMul、OperationDiv 都继承 Operation 类
加减乘除类都需要重写抽象父类的 getResult(),我们将计算逻辑放到 getResult() 里。
public abstract class Operation { public double numberA=0; public double numberB=0; public abstract double getResult(); } public class OperationAdd extends Operation { public double getResult() { double result=0; result = numberA+numberB; return result; } } public class OperationSub extends Operation { public double getResult() { double result=0; result = numberA-numberB; return result; } } public class OperationMul extends Operation { public double getResult() { double result=0; result = numberA*numberB; return result; } } public class OperationDiv extends Operation { public double getResult() { double result=0; result = numberA/numberB; return result; } }
测试方法
public class Test { public static void main(String[] args) { double numberA=1; double numberB=2; //定义引用变量operation用以指向不同的实例(多态)。 Operation opAdd = new OperationAdd(); opAdd.numberA=numberA; opAdd.numberB=numberB; double resultAdd = opAdd.getResult(); System.out.println("resultAdd=="+resultAdd); Operation opSub = new OperationSub(); opSub.numberA=numberA; opSub.numberB=numberB; double resultSub = opSub.getResult(); System.out.println("resultSub=="+resultSub); Operation opMul = new OperationMul(); opMul.numberA=numberA; opMul.numberB=numberB; double resultMul = opMul.getResult(); System.out.println("resultMul=="+resultMul); Operation opDiv = new OperationDiv(); opDiv.numberA=numberA; opDiv.numberB=numberB; double resultDiv = opDiv.getResult(); System.out.println("resultDiv=="+resultDiv); } }
现在程序之间的耦合度大大降低,如果需要添加其他的运算方法,只需创建一个类,继承 Operation 类,实现 getResult() 即可。
二、工厂方法模式
工厂模式介绍:http://www.runoob.com/design-pattern/factory-pattern.html
为什么要用工厂模式?
个人理解:将创建对象这件事进一步封装。调用者原先需要知晓“加减乘除”具体的实现类,现在将创建实现类的任务交给工厂(工厂类负责创建)。调用者不需要知道具体实现类是什么,只需要根据一些特殊标记“+”、“-”、“*”、“/”来获取对象的实例即可
运用工厂模式完善如下:
public class TestFactory { public static Operation creatOperation(String operate) { Operation op = null; switch (operate) { case "+": op = new OperationAdd(); break; case "-": op = new OperationSub(); break; case "*": op = new OperationMul(); break; case "/": op = new OperationDiv(); break; default: break; } return op; } public static void main(String[] args) { // TODO Auto-generated method stub Operation op = null; op = TestFactory.creatOperation("+"); op.numberA=1; op.numberB=2; double result = op.getResult(); System.out.println("result=="+result); } }
上面根据工厂模式的改造已经达到要求了,这里只有一个工厂类,负责创建“加减乘除”类。现在试想一下,如果工厂类不止一个,对“加减乘除”类都增加一个对应的工厂类,会是什么情况?
先构建一个工厂接口
public interface IFactory { Operation createOperation(); }
然后为“加减乘除”各建一个具体工厂去实现 IFactory 接口
public class AddFactory implements IFactory { @Override public Operation createOperation() { return new OperationAdd(); } } public class SubFactory implements IFactory { @Override public Operation createOperation() { return new OperationSub(); } } public class MulFactory implements IFactory { @Override public Operation createOperation() { return new OperationMul(); } } public class DivFactory implements IFactory { @Override public Operation createOperation() { // TODO Auto-generated method stub return new OperationDiv(); } }
测试方法
public class Test { public static void main(String[] args) { IFactory openFactory = new AddFactory(); Operation op = openFactory.createOperation(); op.numberA=1; op.numberB=2; double resultAdd = op.getResult(); System.out.println("resultAdd=="+resultAdd); } }
我们发现,这样的写法不但没有简化代码,而且增加了很多类。原本我们增加一个计算的需求只需要增加一个功能类,再修改工厂类就可以了,现在不但增加功能类,还需要增加对应的工厂类,而且原本调用哪个计算类是由工厂类判断,主程序只需传一个“标记”即可,现在是由主程序自己判断该调用哪个工厂类来获取所需的功能类。
增加了代码却没有减少操作,为什么要这样改变?
我们把第一种模式称为简单工厂模式,第二种模式称为工厂方法模式,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据 main 方法的“标记”动态实例化相关的类,对于 main 方法来说,去除了与具体计算类的依赖。但是这样违反了“开放-封闭原则”,增加计算方法都需要取修改工厂类,不但对扩展开放了,也对修改开放了。于是工厂方法模式来了。
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。
工厂方法模式实现时,main 方法需要去决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,工厂方法把简单工厂的内部逻辑判断移到了 main 方法中进行。想要加功能,本来是改工厂类的,而现在是修改 main 方法。
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个计算方法,就需要加一个计算工厂类,增加了额外的开发量。
至于 main 方法里的判断问题,可以利用“反射”解决。