设计模式(二)工厂模式:简单工厂模式

模拟场景:

 

  现在有如下需求,需要构造一个运算器(Operation)去实现加减乘除的功能,怎么设计?

 

 

思想:

 

  所需要构造的对象是运算器(Operation),因为没有具体功能的运算器,是毫无作用的,所以可以将其定义为抽象类(Abstract Class)。

  需要有具体意义的构造器:加法运算器(OperationAdd),减法运算器(OperationSub),乘法运算器(OperationMul),除法运算器(OperationDiv)。

  根据工厂模式的思想,将这些构造器的创建工作,统一的管理起来,用一个工厂(OperationFactory)去创建。

 

 

UML:

 

  

 

 

分析:

 

  以上是一个简化版(只有加法和减法)的运算器工厂模式 UML 图。

  通过包级别的代码控制,使所有运算器类的构造器,不被外部获得,只能通过 OperationFactory 的 createOperation() 方法完成。

  OperationFactory 的 createOperation()  负责管理所有类的创建,根据入参(在 UML 中未标出)的不同选择不同运算器的初始化。

 

 

代码:

 

1 public abstract class AbsOperation {
2 
3     abstract double calc(double... vals);
4 
5 }
AbsOperation
 1 public final class OperationAdd extends AbsOperation {
 2 
 3     OperationAdd() {
 4 
 5     }
 6 
 7     @Override
 8     public double calc(double... vals) {
 9         double sum = 0;
10         for (double num : vals) {
11             sum += num;
12         }
13         return sum;
14     }
15 
16 }
OperationAdd
1 public enum OperatorEnum {
2 
3     OPERATOR_ADD, OPERATOR_SUB, OPERATOR_MUL, OPERATOR_DIV
4 
5 }
OperatorEnum
 1 public final class OperationFactory {
 2 
 3     public static AbsOperation createOperation(OperatorEnum operator) {
 4         switch (operator) {
 5         case OPERATOR_ADD:
 6             return new OperationAdd();
 7         case OPERATOR_SUB:
 8             return new OperationSub();
 9         case OPERATOR_MUL:
10             return new OperationMul();
11         case OPERATOR_DIV:
12             return new OperationDiv();
13         default:
14             throw new ArithmeticException("未定义的运算类型");
15         }
16     }
17 
18 }
OperationFactory

 

 

反射优化:

 

  通过以上代码分析,工厂根据传入的枚举值,决定到底初始化哪一个运算器类,这么做有2个缺点:

  • 返回类型,是定义的抽象类,如果需要调用子类的个性化方法,需要在外部代码强转。
  • 需要多维护一个枚举类,如果运算器的种类很多,枚举类会变得难以维护,而且 createOperation() 方法会变得很膀肿。

 

  可以通过反射的方式,将 Class 对象作为 createOperation() 方法的入参,利用泛型的特点,避免以上这2个缺点。

 

 1 public final class OperationFactory {
 2 
 3     public static <T extends AbsOperation> T createOperation(Class<T> operationClass) {
 4         try {
 5             return operationClass.newInstance();
 6         } catch (InstantiationException | IllegalAccessException e) {
 7             throw new ArithmeticException("未定义的运算类型");
 8         }
 9     }
10 
11 }
OperationFactory

 

 

考虑单例:

 

  最后再多考虑一件事情,运算器这个东西,比较特殊。

  在整个系统中,并不需要多个运算器对象,也就是说这应该被认为是一个单例的对象。那么,工厂负责管理对象,也需要考虑单例的情况。

  显然,在各个运算器对象中,增加代码来控制单例显然并不现实,那么类似之前说过的第6种单例实现:登记模式,就是一个很好地思想。

  类比而言,Factory 起的作用,和登记模式中的 Registry,差别不大。

 

 1 public final class OperationFactory {
 2 
 3     private static final Map<Class<?>, AbsOperation> operMap = new HashMap<>();
 4 
 5     @SuppressWarnings("unchecked")
 6     public static <T extends AbsOperation> T createOperation3(Class<T> operationClass) {
 7         try {
 8             T t;
 9             if (operMap.containsKey(operationClass)) {
10                 t = (T) operMap.get(operationClass);
11             } else {
12                 t = operationClass.newInstance();
13                 operMap.put(operationClass, t);
14             }
15             return t;
16         } catch (InstantiationException | IllegalAccessException e) {
17             throw new ArithmeticException("未定义的运算类型");
18         }
19     }
20 
21 }
OperationFactory

 

  通过存储一个 Map,将已经创建过的对象,存储在 Map 中,在第二次调用方法时,直接从 Map 中获取对象,从而达到单例的目的。

 

 

总结:

  •   简单工厂模式,由于其工厂对象是独立的,一般都是将其中创建对象的方法设置为 static,避免创建工厂对象,所以也被称为静态工厂模式(Static Factory Method).
  •   由于方法是静态的,导致在实现单例时,代码有点不舒服,就是在需要将 Map 设计为 Class-AbsOperation 结构,导致在具体实现中,需要强转。
  •   简单工厂模式最大的缺点在于,面对新增的类,例如阶乘运算器,不但需要新增一个运算器类,还要对 createOperation() 方法做出改变,这就违反了开闭原则。
  •   这一点,在之后的工厂方法模式(Factory Method)中给出了解决方案。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值