示例
实现两数的加、减、乘、除运算。
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
70 | public Operation newOperation() { |
71 | return new OperationAdd(); |
72 | } |
73 | } |
74 | |
75 | /** |
76 | * SubFactory 减法工厂类 |
77 | */ |
78 | public class SubFactory implements IFactory { |
79 | |
80 | |
81 | public Operation newOperation() { |
82 | return new OperationSub(); |
83 | } |
84 | } |
85 | |
86 | /** |
87 | * MulFactory 乘法工厂类 |
88 | */ |
89 | public class MulFactory implements IFactory { |
90 | |
91 | |
92 | public Operation newOperation() { |
93 | return new OperationMul(); |
94 | } |
95 | } |
96 | |
97 | /** |
98 | * DivFactory 除法工厂类 |
99 | */ |
100 | public class DivFactory implements IFactory { |
101 | |
102 | |
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 | |
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 | |
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 | |
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 | |
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 类的动作放在一个工厂的方法中并返回。