(抽象)工厂模式

示例

实现两数的加、减、乘、除运算。

1
/**
2
 * Operation 运算类
3
 */
4
public class Operation {
5
6
    public static double getResult(double numberA, double numberB, String operate) {
7
        double result = 0;
8
9
        if (Objects.equals(operate, "+")) {
10
            result = numberA + numberB;
11
        } else if (Objects.equals(operate, "-")) {
12
            result = numberA - numberB;
13
        } else if (Objects.equals(operate, "*")) {
14
            result = numberA * numberB;
15
        } else if (Objects.equals(operate, "/")) {
16
            result = numberA / numberB;
17
        }
18
19
        return result;
20
    }
21
}
22
23
24
/**
25
 * Main
26
 */
27
public class Main {
28
29
    public static void main(String[] args) {
30
        double numberA = 20;
31
        double numberB = 15;
32
        String operate = "*";
33
34
        double result = Operation.getResult(numberA, numberB, operate);
35
36
        System.out.println("计算结果是:" + result);
37
    }
38
}

上面的实现方式虽然简单且易于理解,但是当我们再增加一个新的运算(比如立方运算)时,就要对 Operation 类中的运算方法进行修改,这样可能会使得本来运行良好的功能代码发生意外的变化,导致程序发生异常。所以我们需要将代码进行改进。

简单工厂模式

简单工厂模式是属于创建型模式,是工厂模式的一种,是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式。
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)。在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。

使用简单工厂模式改进

简单工厂

1
/**
2
 * Operation
3
 */
4
public interface Operation {
5
6
    double getResult(double numberA, double numberB);
7
}
8
9
/**
10
 * OperationAdd 加法运算
11
 */
12
public class OperationAdd implements Operation {
13
14
    @Override
15
    public double getResult(double numberA, double numberB) {
16
        return numberA + numberB;
17
    }
18
}
19
20
/**
21
 * OperationSub 减法运算
22
 */
23
public class OperationSub implements Operation {
24
25
    @Override
26
    public double getResult(double numberA, double numberB) {
27
        return numberA - numberB;
28
    }
29
}
30
31
/**
32
 * OperationMul 乘法运算
33
 */
34
public class OperationMul implements Operation {
35
36
    @Override
37
    public double getResult(double numberA, double numberB) {
38
        return numberA * numberB;
39
    }
40
}
41
42
/**
43
 * OperationDiv 除法运算
44
 */
45
public class OperationDiv implements Operation {
46
47
    @Override
48
    public double getResult(double numberA, double numberB) {
49
        if (numberB == 0) {
50
            throw new ArithmeticException("除数不能为 0!");
51
        }
52
        return numberA / numberB;
53
    }
54
}
55
56
/**
57
 * SimpleFactory
58
 */
59
public class SimpleFactory {
60
61
    public static Operation newOperation(String operate) {
62
63
        Operation operation = null;
64
        if (Objects.equals(operate, "+")) {
65
            operation = new OperationAdd();
66
        } else if (Objects.equals(operate, "-")) {
67
            operation = new OperationSub();
68
        } else if (Objects.equals(operate, "*")) {
69
            operation = new OperationMul();
70
        } else if (Objects.equals(operate, "/")) {
71
            operation = new OperationDiv();
72
        }
73
74
        return operation;
75
    }
76
}
77
78
/**
79
 * Main
80
 */
81
public class Main {
82
83
    public static void main(String[] args) {
84
        double numberA = 20;
85
        double numberB = 15;
86
        String operate = "*";
87
88
        Operation operation = SimpleFactory.newOperation(operate);
89
        double result = operation.getResult(numberA, numberB);
90
91
        System.out.println(result);
92
    }
93
}

如果我们需要对其中的运算进行修改,只需修改它相应的运算类即可;如果需要增加新的运算方式,只需增加相应的运算子类,然后在工厂类里增加一个判断分支,添加相应的实例化代码。

简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是每当要增加一个新的功能时,都要到工厂类的方法里增加一个分支条件,这样就违背了开放封闭原则。

工厂方法模式

工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

使用工厂方法模式改进

工厂方法

1
/**
2
 * Operation
3
 */
4
public interface Operation {
5
6
    double getResult(double numberA, double numberB);
7
}
8
9
/**
10
 * OperationAdd 加法运算
11
 */
12
public class OperationAdd implements Operation {
13
14
    @Override
15
    public double getResult(double numberA, double numberB) {
16
        return numberA + numberB;
17
    }
18
}
19
20
/**
21
 * OperationSub 减法运算
22
 */
23
public class OperationSub implements Operation {
24
25
    @Override
26
    public double getResult(double numberA, double numberB) {
27
        return numberA - numberB;
28
    }
29
}
30
31
/**
32
 * OperationMul 乘法运算
33
 */
34
public class OperationMul implements Operation {
35
36
    @Override
37
    public double getResult(double numberA, double numberB) {
38
        return numberA * numberB;
39
    }
40
}
41
42
/**
43
 * OperationDiv 除法运算
44
 */
45
public class OperationDiv implements Operation {
46
47
    @Override
48
    public double getResult(double numberA, double numberB) {
49
        if (numberB == 0) {
50
            throw new ArithmeticException("除数不能为 0!");
51
        }
52
        return numberA / numberB;
53
    }
54
}
55
56
/**
57
 * IFactory
58
 */
59
public interface IFactory {
60
61
    Operation newOperation();
62
}
63
64
/**
65
 * AddFactory 加法工厂类
66
 */
67
public class AddFactory implements IFactory {
68
69
    @Override
70
    public Operation newOperation() {
71
        return new OperationAdd();
72
    }
73
}
74
75
/**
76
 * SubFactory 减法工厂类
77
 */
78
public class SubFactory implements IFactory {
79
80
    @Override
81
    public Operation newOperation() {
82
        return new OperationSub();
83
    }
84
}
85
86
/**
87
 * MulFactory 乘法工厂类
88
 */
89
public class MulFactory implements IFactory {
90
91
    @Override
92
    public Operation newOperation() {
93
        return new OperationMul();
94
    }
95
}
96
97
/**
98
 * DivFactory 除法工厂类
99
 */
100
public class DivFactory implements IFactory {
101
102
    @Override
103
    public Operation newOperation() {
104
        return new OperationDiv();
105
    }
106
}
107
108
/**
109
 * Main
110
 */
111
public class Main {
112
113
    public static void main(String[] args) {
114
        double numberA = 20;
115
        double numberB = 15;
116
        MulFactory mulFactory = new MulFactory();
117
        Operation operation = mulFactory.newOperation();
118
        double result = operation.getResult(numberA, numberB);
119
120
        System.out.println(result);
121
    }
122
}

工厂方法模式,克服了简单工厂模式违背开放封闭原则的缺点,又保持了封装对象创建过程的优点。它们都是集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可实现,降低了客户程序与产品对象的耦合。

工厂方法模式,是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量。

抽象工厂模式

抽象工厂模式定义了一个接口用于创建相关或有依赖关系的对象簇,而无需指明且体的类。抽象工厂模式是将简单工厂模式和工厂方法模式进行整合。从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。将工厂抽象成两层,抽象工厂和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展。

使用抽象工厂模式改进

抽象工厂

1
/**
2
 * Operation
3
 */
4
public interface Operation {
5
6
    double getResult(double numberA, double numberB);
7
}
8
9
/**
10
 * OperationAdd 加法运算
11
 */
12
public class OperationAdd implements Operation {
13
14
    @Override
15
    public double getResult(double numberA, double numberB) {
16
        return numberA + numberB;
17
    }
18
}
19
20
/**
21
 * OperationSub 减法运算
22
 */
23
public class OperationSub implements Operation {
24
25
    @Override
26
    public double getResult(double numberA, double numberB) {
27
        return numberA - numberB;
28
    }
29
}
30
31
/**
32
 * OperationMul 乘法运算
33
 */
34
public class OperationMul implements Operation {
35
36
    @Override
37
    public double getResult(double numberA, double numberB) {
38
        return numberA * numberB;
39
    }
40
}
41
42
/**
43
 * OperationDiv 除法运算
44
 */
45
public class OperationDiv implements Operation {
46
47
    @Override
48
    public double getResult(double numberA, double numberB) {
49
        if (numberB == 0) {
50
            throw new ArithmeticException("除数不能为 0!");
51
        }
52
        return numberA / numberB;
53
    }
54
}
55
56
/**
57
 * OperationAccess 利用反射技术实例化对象
58
 */
59
public class OperationAccess {
60
61
    public static Operation createOperation(Class<? extends Operation> clazz) {
62
        Operation operation = null;
63
        try {
64
            operation = clazz.newInstance();
65
        } catch (InstantiationException e) {
66
            e.printStackTrace();
67
        } catch (IllegalAccessException e) {
68
            e.printStackTrace();
69
        }
70
        return operation;
71
    }
72
}

一般来说,所有在用简单工厂的地方,都可以考虑用反射技术来去除 switch 或 if,解除分支判断带来的耦合。

小结

工厂模式是将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到与主项目的依赖关系的解耦目的,从而提高项目的扩展和维护性。创建对象实例时,不要直接 new 类,而是把这个 new 类的动作放在一个工厂的方法中并返回。