意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
结构:
实例:下面我们以Pizza店的例子来谈谈“工厂方法模式”的来龙去脉,我们学习的思路是“原始设计-->简单工厂-->工厂方法”。
情景分析:假如你有一个Pizza店,那么你的Pizza订单可能会写成如下代码(这段代码写在PizzaStore类里面):

2



3

4

5

6

7

8

9

10

如果你的Pizza店的Pizza有很多类,那么你的Pizza订单会如何写呢,可能会写成如下:

2



3

4



5

6

7



8

9

10

11



12

13

14

15



16

17

18

19

20

21

22

23

24

25

26

27

上面的代码有一个问题:当Pizza的种类发生改变(或增加或减少)时,这段代码必须重写。那么这段代码应该如何改进呢?其实我们只要封装变化点就行了,即代码中的“if,else”语句。封装的过程如下:
1)、创建SimplePizzaFactory类。
2)、在SimplePizzaFactory类中创建CreatPizza方法。
3)、把“if,else”语句写道CreatPizza方法中。
相应的代码如下:

2



3

4



5

6

7



8

9

10

11



12

13

14

15



16

17

18

19

20

21

这样做的好处:
1)、可以很好的达到代码重用。如果其他类想得到Pizza,都可以调用SimplePizzaFactory的CreatPizza()方法。
2)、维护方便。如果Pizza的创建需要改变,只需要改变CreatPizza()方法就行了,其他调用的地方不需要发生改变。
值得改进的地方:可以把CreatPizza()写成静态方法。
改成静态方法的优点:不需要通过创建对象来使用类里的方法。
缺点:不能通过继承来改变创建对象的行为。
小结:
上面的代码其实是简单工厂模式的应用(简单工厂不是一个真正的模式)。
简单工厂(Simple Factory)模式的意图:Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例。通常它返回的类都有一个公共的父类和公共的方法。
结构:
工厂类角色Creator (SimplePizzaFactory):工厂类在客户端的直接控制下(Create方法)创建产品对象。
抽象产品角色Product (Pizza):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
具体产品角色ConcreteProduct (CheesePizza, GreekPizza,PepperoniPizza):定义工厂具体加工出的对象。
客户端Client(PizzaStore):负责调用SimplePizzaFactory的Create方法。
其实SimplePizzaFactory的CreatPizza()方法并没有符合面向对象的开闭原则,它没有对修改进行关闭,即当Pizza的种类改变时,这个方法必须重写,只不过改动的工作量减少了,只需要改动一处,其他调用的地方不需要变动而已。
新的需求:
1)、Pizza店有了加盟店,加盟店生产Pizza的流程应该一成不变。
2)、每个加盟店可能要提供不同风味的Pizza(比如纽约、芝加哥、加州)。
按照简单工厂的方法,我们可以这样做:创建NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory类。相应的代码如下:

2

3

如果需求不发生改变,那么用简单工厂就已经足够了,但是一旦需求发生了变化,简单工厂就不能适应了。
变化后的需求:
1)、有些加盟店采用自创的流程,比如烘烤的做法有些差异(Bake方法改变)、不要切片(Cut方法不要)、采用其他公司的盒子(Box方法改变)等。
2)、Pizza的种类有可能发生改变(或增加或减少)。
我们的做法很简单,具体操作:
1)、把SimpleFactory的CreatPizza()方法写回到PizzaStore里面。
2)、抽象PizzaStore,用NYPizzaStore、ChicagoPizzaStore等继承PizzaStore。
3)、具体的PizzaStore和具体的Pizza进行一一对应。
相应的类图如下(应用了工厂方法模式):
说明:
1)、PizzaStore类是抽象类,相当于工厂方法模式的Creator类,NYPizzaStore类和ChicagoPizzaStore类继承了PizzaStore,相当于工厂方法模式的ConcreteCreator。
2)、Pizza是抽象类,相当于Product类,NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类、ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类继承了Pizza类,相当于ConcreteProduct。
3)、NYPizzaStore类调用了NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类,ChicagoPizzaStore类调用了ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类。
相应的代码如下:


1

2



3

4



5

6

7

8

9

10

11

12

13

14

15

16

17

18



19

20



21

22

23



24

25

26

27



28

29

30

31



32

33

34

35

36

37

38



39

40



41

42

43



44

45

46

47



48

49

50

51



52

53

54

55

56

57

58



59

60

61

62



63

64

65

66

67

68

69

70

71

72



73

74

75

76

77

78

79



80

81


82


83

84

85



86

87

88

89

90

91



92

93

94

95

96



97

98

99

100

101



102

103

104

105

106



107

108

109

110

111



112

113



114

115

116

117

118

119

120

121

122



123

124

125

126

127



128

129



130

131

132

133

134

135

136

工厂方法模式的特点:
1)、核心的工厂类不负责所有产品的创建,而是将具体创建工作交给子类去做,可以允许系统在不修改工厂角色的情况下引进新产品。
2)、工厂类与产品类往往具有平行的等级结构,它们之间一一对应。
工厂方法和简单工厂的区别:
1)、Factory Method 的核心是一个抽象工厂类,而Simple Factory 把核心放在一个具体类上。
2)、Factory Method 的具体工厂类都有共同的接口,或者有共同的抽象父类。
3)、当系统扩展需要添加新的产品对象时,Factory Method仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而Simple Factory 在添加新产品对象后不得不修改工厂方法,扩展性不好。
参考文献:
《Head.First设计模式》
吕震宇 设计模式系列