1 工厂模式介绍
1.1 定义:定义一个用于创建对象的接口,让子类绝对实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
工厂方法模式通用类图:
在工厂模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义,Creator为抽象类创建类,也就是抽象工厂,具体如何创建产品类是有具体的实现工厂ConcreteCreator完成的。
1.2 工厂方法模式的优点
- 良好的封装性,代码结构清晰。
- 扩展性非常优秀,在增加产品类的情况系下,只有适当的修改具体的工厂类或扩展一个工厂类,就可以“拥抱变化”。
- 屏蔽产品类。产品类的实现如何变化,调用者无需关心,它只需关心产品的接口,只要接口保持不变,系统中的上层模块就不需要发生变化。
- 解耦框架。高层模块只需要知道产品的抽象类,其他实现类都不用关心。
1.3 工厂方法模式的使用场景
2 工厂模式实现
2.1 简单工厂模式(静态工厂模式)
以实现一个计算器为例:
整个过程涉及到三个对象,人(Program4类表示)、计算器(以OperationFactory类表示)、计算方式(计算方式中有多种,加减乘除等,但都属于计算方法,以一个父类Operation,加减乘除继承覆写方法即可)。整个示例类如下图:
1 public class Program4 { 2 public static void main(String[] args) { 3 try { 4 Scanner scanner = new Scanner (System.in); 5 6 System.out.println ("请输入数字A:"); 7 double numberA = Double.parseDouble (scanner.nextLine ()); 8 System.out.println ("选择运算符(+、-、*、/):"); 9 String strOperate = scanner.nextLine ();10 System.out.println ("请输入数字B:");11 double numberB = Double.parseDouble (scanner.nextLine ());12 String strResult = "";13 14 if ( strOperate != "/" || numberB != 0){15 Operation oper;16 oper = OperationFactory.createOperate (strOperate);17 oper.setNumberA (numberA);18 oper.setNumberB (numberB);19 20 strResult = String.valueOf (oper.getResult ());21 System.out.println ("结果为:"+strResult);22 23 }else {24 System.out.println ("除数不能为零");25 }26 27 scanner.close ();28 } catch (Exception e) {29 throw new RuntimeException("您输入有误:"+e.getMessage ());30 }31 }32 }
计算器(工厂)根据用户需求,选择(生成)符合需要的计算方式创建对应的实例对象,创建过程中需要需用户参与。
1 public class OperationFactory { 2 public static Operation createOperate(String operate) { 3 Operation oper = null; 4 switch (operate){ 5 case "+": 6 oper = new OperationAdd (); 7 break; 8 case "-": 9 oper = new OperationSub ();10 break;11 case "*":12 oper = new OperationMul ();13 break;14 case "/":15 oper = new OperationDiv ();16 break;17 }18 return oper;19 }20 }
1 public class Operation{ 2 private double numberA = 0; 3 private double numberB = 0; 4 5 public double getNumberA() { return numberA; } 6 7 public void setNumberA(double numberA) { this.numberA = numberA; } 8 9 public double getNumberB() { return numberB; }10 11 public void setNumberB(double numberB) { this.numberB = numberB; }12 13 public double getResult(){ 14 double result = 0;15 return result;16 }17 }18 19 class OperationAdd extends Operation{20 @Override21 public double getResult() {22 double result = 0;23 result = getNumberA () + getNumberB ();24 return result;25 }26 }27 28 class OperationSub extends Operation{29 @Override30 public double getResult() {31 double result = 0;32 result = getNumberA () - getNumberB ();33 return result;34 }35 }36 37 class OperationMul extends Operation{38 @Override39 public double getResult() {40 double result = 0;41 result = getNumberA () * getNumberB ();42 return result;43 }44 }45 46 class OperationDiv extends Operation{47 @Override48 public double getResult() {49 double result = 0;50 result = getNumberA () / getNumberB ();51 return result;52 }53 }
简单工厂的缺点,不符合“开放封闭原则,要增加新的功能(计算方式)时,需要去修改工厂类(增加分支)。
2.2 多方法模式
是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
1 public class OperationFactory03 { 2 3 public Operation add(){ 4 return new OperationAdd(); 5 } 6 7 public Operation sub(){ 8 return new OperationSub (); 9 }10 11 public Operation mul(){12 return new OperationMul();13 }14 15 public Operation div(){16 return new OperationDiv();17 }18 }
1 public class FactoryTest { 2 3 public static void main(String[] args) { 4 5 OperationFactory03 factory03 = new OperationFactory03(); 6 Operation add = factory03.add(); 7 8 add.setNumberA(20); 9 add.setNumberB(10);10 double result = add.getResult();11 System.out.println(result);12 }13 }
2.3 静态工厂方法模式
多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
1 public class OperationFactory { 2 3 public static Operation add(){ 4 return new OperationAdd(); 5 } 6 7 public static Operation sub(){ 8 return new OperationSub (); 9 }10 11 public static Operation mul(){12 return new OperationMul();13 }14 15 public static Operation div(){16 return new OperationDiv();17 }18 }
1 //调用类 2 public class FactoryTest { 3 4 public static void main(String[] args) { 5 6 Operation add = OperationFactory02.add(); 7 add.setNumberA(20); 8 add.setNumberB(10); 9 double result = add.getResult();10 System.out.println(result);11 12 }13 }
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传 入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
3 抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑, 有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象 工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。
接口类
1 public interface Sender {2 public void Send();3 }
两个实现类
1 public class MsgSender implements Sender{2 3 @Override4 public void Send() {5 System.out.println("this is msgsender");6 }7 }
1 public class MailSender implements Sender {2 3 @Override4 public void Send() {5 System.out.println("this is mailsender!");6 }7 }
两个工厂类
1 public class SendmsgFactory implements Provider {2 3 @Override4 public Sender produce() {5 return new MsgSender();6 }7 }
1 public class SendmailFactory implements Provider {2 3 @Override4 public Sender produce() {5 return new MailSender();6 }7 }
提供一个接口
1 public interface Provider {2 public Sender produce();3 }
测试类
1 public class FactoryTest {2 public static void main(String[] args) {3 Provider provider = new SendmailFactory();4 Sender sender = provider.produce();5 sender.Send();6 }7 }
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好,即依赖抽象不依赖具体原则的体现。