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 @Override 21 public double getResult() { 22 double result = 0; 23 result = getNumberA () + getNumberB (); 24 return result; 25 } 26 } 27 28 class OperationSub extends Operation{ 29 @Override 30 public double getResult() { 31 double result = 0; 32 result = getNumberA () - getNumberB (); 33 return result; 34 } 35 } 36 37 class OperationMul extends Operation{ 38 @Override 39 public double getResult() { 40 double result = 0; 41 result = getNumberA () * getNumberB (); 42 return result; 43 } 44 } 45 46 class OperationDiv extends Operation{ 47 @Override 48 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 @Override 4 public void Send() { 5 System.out.println("this is msgsender"); 6 } 7 }
1 public class MailSender implements Sender { 2 3 @Override 4 public void Send() { 5 System.out.println("this is mailsender!"); 6 } 7 }
两个工厂类
1 public class SendmsgFactory implements Provider { 2 3 @Override 4 public Sender produce() { 5 return new MsgSender(); 6 } 7 }
1 public class SendmailFactory implements Provider { 2 3 @Override 4 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了,无需去改动现成的代码。这样做,拓展性较好,即依赖抽象不依赖具体原则的体现。