1. 程式人生 > >一文詳解“抽象工廠模式”以及python語言的實現

一文詳解“抽象工廠模式”以及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類

由此可見,牽一髮而動全身,很麻煩。

 

終極總結:抽象工廠模式:對於同一系列的集中式生產,對於不同系列的分散式生產,但是型別的建立不是由工廠函式直接完成,而是圍繞一個“超級工廠”去搭建的