一文詳解“抽象工廠模式”以及python語言的實現
一、什麼是“抽象工廠模式”——Abstract Factory Pattern
其實所謂的抽象工廠模式,是在前面講解過的“簡單工廠模式”、“工廠方法模式”的基礎之上進行擴充的。回憶前面的這兩種模式,我們可以得出:
工廠模式:針對一個系列的類(比如Circle、Rectangle、Ellipse、Triangle),它們有很多的共同點,很多書籍或者是文章將他們稱之為一個系列的產品,通俗的說就是一個系列的類。使用一個工廠,用一個工廠建立函式去建立某一個類。
一系列類——>一個工廠——>一個建立函式——>某一個具體的類
工廠方法模式:針對一系列的類(比如Circle、Rectangle、Ellipse、Triangle),使用一個抽象的工廠介面,然後然後為每一個具體的類都編寫一個工廠類,然後再在每一個類中用建立函式建立。
一系列類——>一個抽象工廠介面——>多個與系列對應的工廠類——>每個類有一個建立函式——>某一個具體的類
總結:簡單工廠模式是籠統的承包服務,不管有多少個類需要建立,全部都由一個工廠去完成;
工廠函式模式是定製化的一對一服務,每一個工廠只能建立某一種特定的類,但是這些工廠統一遵循總工廠指定的原則(即抽象工廠介面的建立方法)。
那什麼又是抽象工廠模式?
抽象工廠模式是“分類之後的一對一服務”,我們有多個系列的類需要建立,讓某一個工廠專門負責某一類物件的建立,另一個工廠負責另外一類的物件建立(看到這裡的小夥伴懵逼了,這不就是簡單工廠模式嗎?不就是多了幾個工廠嗎?沒什麼區別啊, 好像是的),但是區別還是有的,後面會講到。
總結:
簡單工廠模式:集中式生產
工廠方法模式:分散式成產
抽象工廠模式:對於同一系列的集中式生產,對於不同系列的分散式生產(這不就是前二者的結合嘛)
二、抽象工廠模式的使用情景
當出現一系列的產品族的時候,即出現很多的類的時候,而且這些類可以進行很好的分組,這個時候使用抽象工廠模式最為適合。為什麼?因為此時如果使用簡單工廠模式,則會導致那一個工廠任務繁重(因為要生產很多的類),而且各個類之間沒有區分度;如果使用工廠函式模式,每一個類要使用一個新的工廠(一對一服務),那麼則需要建立太多的類了,導致程式碼臃腫;最好的辦法就是現根據類的資訊對各個系列的類進行分組處理,比如分成A、B、C三組,然後每一組由一個工廠類去完成,這樣既體現了一對一的定製服務(先分組)又體現了工廠的集中生產(每一個工廠生產一類)
三、抽象工廠模式的python程式碼實現
比如我有很多的類需要定義,包括形狀(比如Circle、Rectangle、Ellipse、Triangle),顏色類(比如Red、Blue、Black等等)
下面我將從一個“四步走”策略完整實現抽象工廠模式“
1、第一步,先定義形狀類這個系列
import math
#定義一個“形狀”的介面,裡面定義一個面積的介面方法,只有方法的定義,並沒有實現體
class IShape(object):
def Area(self):
pass
#定義4個圖形類,都是實現Ishape介面,並且每一個圖形都有一個可以計算面積的方法,相當於重寫介面方法
class Circle(IShape):
def Area(self,radius):
return math.pow(radius,2)*math.pi
class Rectangle(IShape):
def Area(self,longth,width):
return 2*longth*width
class Triangle(IShape):
def Area(self,baselong,height):
return baselong*height/2
class Ellipse(IShape):
def Area(self,long_a,short_b):
return long_a*short_b*math.pi
2、第二步,再定義顏色類這個系列
#定義一個“顏色”的介面,裡面定義一個顏色名稱的介面方法,只有方法的定義,並沒有實現體
class IColor(object):
def color(self):
pass
#定義3個顏色類,都是實現IColor介面,並且每一個圖形都有一個可以獲取顏色名稱的方法,相當於重寫介面方法
class Red(IColor):
def color(self,name):
print(f'我的顏色是:{name}')
class Blue(IColor):
def color(self,name):
print(f'我的顏色是:{name}')
class Black(IColor):
def color(self,name):
print(f'我的顏色是:{name}')
3、第三步,定義抽象工廠以及與每一個系列對應的工廠
class IFactory: #模擬介面
def create_shape(self): #定義介面的方法,只提供方法的宣告,不提供方法的具體實現
pass
def create_color(self):
pass
#建立形狀這一個系列的工廠
class ShapeFactory(IFactory): #模擬型別實現某一個介面,實際上是類的繼承
def create_shape(self, name): #重寫介面中的方法
if name =='Circle':
return Circle()
elif name == 'Rectangle':
return Rectangle()
elif name == 'Triangle':
return Triangle()
elif name == 'Ellipse':
return Ellipse()
else:
return None
#建立顏色這一個系列的工廠
class ColorFactory(IFactory): #模擬型別實現某一個介面,實際上是類的繼承
def create_color(self, name): #重寫介面中的方法
if name =='Red':
return Red()
elif name =='Blue':
return Blue()
elif name =='Black':
return Black()
else:
return None
注意:這裡的抽象工廠和“工廠方法模式裡面的抽象工廠有點區別,因為這裡有兩個系列的型別需要產生,所以,抽象工廠裡面需要有兩個函式介面,一個產生”形狀“,一個產生”顏色“,然後再在實現該介面的工廠中分別進行重寫。
4、第四步,定義產生工廠類的類——抽象工廠模式的核心所在
#定義一個專門產生工廠的類
class FactoryProducer:
def get_factory(self,name):
if name=='Shape':
return ShapeFactory()
elif name=='Color':
return ColorFactory()
else:
return None
注意:這一步是抽象工廠模式最為與眾不同的,如果按照 “簡單工廠模式 ”,只需要進行到第三步即可,因為然後我分別使用 ShapeFactory工廠類和ColorFactory類去分別產生每一個系列的類的例項即可,但是我們沒有這麼做。而是再定義一個新的
“ 工廠產生類 ”去讓我們決定到底是要產生哪個類的例項。
總結:
抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠建立其他工廠。該超級工廠又稱為其他工廠的工廠。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。(這裡的FactoryProducer就是超級工廠)
在抽象工廠模式中,介面是負責建立一個相關物件的工廠,不需要顯式指定它們的類。每個生成的工廠都能按照工廠模式提供物件。
5、執行結果如下:
if __name__=='__main__':
factory_producer=FactoryProducer()
shape_factory=factory_producer.get_factory('Shape')
color_factory=factory_producer.get_factory('Color')
#--------------------------------------------------------------
circle=shape_factory.create_shape('Circle')
circle_area=circle.Area(2)
print(f'這是一個圓,它的面積是:{circle_area}')
rectangle=shape_factory.create_shape('Rectangle')
rectangle_area=rectangle.Area(2,3)
print(f'這是一個長方形,它的面積是:{rectangle_area}')
triangle=shape_factory.create_shape('Triangle')
triangle_area=triangle.Area(2,3)
print(f'這是一個三角形,它的面積是:{triangle_area}')
ellipse=shape_factory.create_shape('Ellipse')
ellipse_area=ellipse.Area(3,2)
print(f'這是一個橢圓,它的面積是:{ellipse_area}')
#---------------------------------------------------------------
red=color_factory.create_color('Red')
red.color('紅色')
blue=color_factory.create_color('Blue')
blue.color('藍色')
black=color_factory.create_color('Black')
black.color('黑色')
執行結果如下:
這是一個圓,它的面積是:12.566370614359172
這是一個長方形,它的面積是:12
這是一個三角形,它的面積是:3.0
這是一個橢圓,它的面積是:18.84955592153876
我的顏色是:紅色
我的顏色是:藍色
我的顏色是:黑色
四、抽象工廠模式總結
1、對比
再來看看工廠方法模式與抽象工廠模式對比:
工廠方法模式 |
抽象工廠模式 |
針對的是一個產品等級結構 | 針對的是面向多個產品等級結構 |
一個抽象產品類 | 多個抽象產品類 |
可以派生出多個具體產品類 | 每個抽象產品類可以派生出多個具體產品類 |
一個抽象工廠類,可以派生出多個具體工廠類 | 一個抽象工廠類,可以派生出多個具體工廠類 |
每個具體工廠類只能建立一個具體產品類的例項 | 每個具體工廠類可以建立多個具體產品類的例項 |
2、優點:
對於出現多系列的型別,建立邏輯清楚,因為是分門別類進行建立的;結合了“簡單工廠模式”和“工廠方法模式”的優點
3、缺點
一系列產品族擴充套件非常困難,要增加一個系列的某一產品,既要在抽象的 Creator 里加程式碼,又要在具體的裡面加程式碼。
比如,我還要在增加一系列的材質型別(包括Stone、Wood、Plastic等)。
首先,我需要再定義一個抽象材質介面,然後定義很多的類去實現這個介面;
然後,我需要在抽象工廠介面中新增一個create_material()方法,並且還需要實現一個MaterialFactory工廠類;
最後,我還需要更改超級工廠FactoryProducer類
由此可見,牽一髮而動全身,很麻煩。
終極總結:抽象工廠模式:對於同一系列的集中式生產,對於不同系列的分散式生產,但是型別的建立不是由工廠函式直接完成,而是圍繞一個“超級工廠”去搭建的