标签:
前面我们讲了三个工厂模式,都是万变不离其宗,利用工厂模式来实例化不同的对象,虽然可能会多写一些代码,但这会为程序系统带来更方便的扩展性和尽量小的修改。
我们来从头回顾一下为什么要用工厂模式,实现一个计算器的程序,初级程序员可能立马分分钟就能写出代码来,例如:
1 package day_4_summary; 2 3 /** 4 * 计算器 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public class Calc { 10 public static void main(String[] args){ 11 double numA = 1; 12 double numB = 2; 13 String opt = "+"; 14 double result = 0; 15 16 if (opt.equals("+")){ 17 result = numA + numB; 18 } 19 if (opt.equals("-")){ 20 result = numA - numB; 21 } 22 if (opt.equals("*")){ 23 result = numA * numB; 24 } 25 if (opt.equals("/")){ 26 result = numA / numB; //我们这里暂不考虑除数为0的情况 27 } 28 29 System.out.println("result=" + result); 30 } 31 }
几乎是20行的代码就实现了需求,但“合适”不呢?这种写法,是初学编程时C语言面向过程的编程方式,这种方式可能会伴随我们很久很久,就算学到了面向对象语言,这种思维方式也会很久很久挥之不去。4个if,要做4次判断,有人说那我用else if,我用switch不就可以了吗?
面向对象编程不是用一门面向对象的语言来编程。
面向对象编程,让我们可维护、可复用、可扩展,低耦合、高内聚,这些到底是什么呢?我们用面向对象的编程方法来实现这个计算器,并且使用用简单工厂模式。
我们首先画出简单工厂模式的UML类图,把加减乘除抽象成一个运算类,这里就能做到了可复用,如果还有开方、乘方运算再实现运算类就可以了,这就是可扩展。
抽象运算类:
1 package day_4_summary; 2 3 /** 4 * 抽象运算类 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public abstract class AbstractOption { 10 private double numA; 11 private double numB; 12 public double getNumA() { 13 return numA; 14 } 15 public void setNumA(double numA) { 16 this.numA = numA; 17 } 18 public double getNumB() { 19 return numB; 20 } 21 public void setNumB(double numB) { 22 this.numB = numB; 23 } 24 25 public abstract double getResult(); 26 }
实现抽象运算类,只举加法:
1 package day_4_summary; 2 3 /** 4 * 加法类 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public class OptionAdd extends AbstractOption { 10 11 /* (non-Javadoc) 12 * @see day_4_summary.AbstractOption#getResult() 13 */ 14 @Override 15 public double getResult() { 16 17 return super.getNumA() + super.getNumB(); 18 } 19 20 }
工厂类,用来负责实例化具体对象:
package day_4_summary; /** * 工厂类 * @author turbo * * 2016年9月7日 */ public class OptionFactory { public static AbstractOption CreateOption(String opt){ AbstractOption option = null; switch (opt) { case "+" : option = new OptionAdd(); break; case "-" : //创建减法运算符类 break; case "*" : //创建乘法运算类 break; case "/" : //创建除法运算类 break; default : break; } return option; } }
客户端:
1 package day_4_summary; 2 3 /** 4 * 客户端 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public class Main { 10 11 /** 12 * @param args 13 */ 14 public static void main(String[] args) { 15 AbstractOption option = OptionFactory.CreateOption("+"); 16 double result = 0.0; 17 option.setNumA(1); 18 option.setNumB(2); 19 result = option.getResult(); 20 } 21 22 }
这样我们就用简单工厂模式实现了一个计算器,比起面向过程的编程方式,这样是不是有点感觉了呢?我们想要加法,只需将“+”传递给工厂类让它帮我们实例化一个加法运算类即可,我们不用管它是如何实现的。其他人想用加法时,只需调用这个工厂类来实例化即可,我们把工厂类的接口提供给他,他不用去管是怎么实现的,他只管用,这不就是可复用吗?
如果,我要增加一个开方运算,你要实现一个更复杂的运算,那我们俩都要同时去修改工厂类里的代码,这将使得代码的维护性变得很差,能不能提供给我们一个接口,让我们自己去实现我们想要做的运算呢?这个时候就得用工厂方法模式了。
同样,我们首先画出UML类图:
应该能明白了吧?如果要新增一个运算方式,我们只需实现操作类和实现工厂类即可,而不必在原有代码的基础上做修改。
抽象运算类和加法类不变,还是和上面的代码一样,我们主要来看工厂类的变化,此时工厂类变成了一个接口。
1 package day_4_summary; 2 3 /** 4 * 工厂接口类 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public interface IFactory { 10 AbstractOption createOption(); 11 }
接着实现加法工厂类,省去其他运算工厂类。
1 package day_4_summary; 2 3 /** 4 * 加法工厂类 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public class OperationAddFactory implements IFactory { 10 11 /* (non-Javadoc) 12 * @see day_4_summary.IFactory#createOption() 13 */ 14 @Override 15 public AbstractOption createOption() { 16 17 return new OptionAdd(); 18 } 19 20 }
客户端代码:
1 package day_4_summary; 2 3 /** 4 * 客户端 5 * @author turbo 6 * 7 * 2016年9月7日 8 */ 9 public class Main { 10 11 /** 12 * @param args 13 */ 14 public static void main(String[] args) { 15 IFactory factory = new OperationAddFactory(); 16 AbstractOption option = factory.createOption(); 17 double result = 0.0; 18 option.setNumA(1); 19 option.setNumB(1); 20 result = option.getResult(); 21 System.out.println(result); 22 } 23 24 }
这两者主要的区别就是上面说的,如果要新增一个运算类,简单工厂模式我得要在原有代码基础上修改,如果是工厂方法模式,我只需再实现工厂接口类即可,而不用再原有代码上做修改。
至于抽象工厂方法,上一篇说的比较详细,这里主要是对比简单工厂模式和工厂方法模式,掌握了工厂方法模式后,即会抽象工厂模式。在抽象工厂模式中利用反射机制,这个值得研究一下。在后续会仔细研究一下Java的反射机制。
标签:
原文地址:http://www.cnblogs.com/yulinfeng/p/5851560.html