用Python實現設計模式——建造者模式和原型模式

夏秋發表於2019-02-16

前言

前兩篇文章介紹了單例模式和工廠模式,這兩種設計模式實際上都屬於軟體工程中的建立型模式(Creational Pattern)。維基百科有對這類模式的定義:

軟體工程中,建立型模式 是處理物件 “物件 (電腦科學)”)建立的設計模式 “設計模式 (計算機)”),試圖根據實際情況使用合適的方式建立物件。基本的物件建立方式可能會導致設計上的問題,或增加設計的複雜度。建立型模式通過以某種方式控制物件的建立來解決問題。
建立型模式由兩個主導思想構成。一是將系統使用的具體類封裝起來,二是隱藏這些具體類的例項建立和結合的方式。

實際上建立型模式的最大作用就是把物件的建立過程和使用過程進行了解耦,對使用者只提供介面而隱藏了具體的實現細節,讓軟體結構更清晰,更符合單一職責的原則。接下來本文將繼續介紹建立型模式中的另兩種模式——建造者模式和原型模式,文中的程式碼已託管在Github上。

建造者模式

建造者模式(Builder Pattern)與工廠模式類似,也是把產品的例項化過程交給專門的類來實現,不同的是建造者模式更多的是針對現實中一些構成較複雜,有多個組成部分的物件。比如像汽車就由車身、發動機、車輪、方向盤等很多部件組成,而且整個組裝的過程可能還要安裝一定的順序進行。

class Car(object):
    """產品
    """
    def __init__(self, name):
        self.name = name
        self.body = None
        self.engine = None
        self.tire = None

    def __str__(self):
        info = ("Name: {}".format(self.name),
                "Body: {}".format(self.body),
                "Engine: {}".format(self.engine),
                "Tire: {}".format(self.tire))
        return `
`.join(info)

但是在現實使用時,使用者可能並不關心汽車的這些細節和如何將這些部件組裝成汽車的,而只是想通過特定的介面和引數獲得汽車這個物件。這時就需要將這個複雜的過程抽象到到一個被稱作建造者的物件裡,建造者來負責構造這些複雜的組成:

class CarBuilder(object):
    """建造者
    """
    def __init__(self):
        self.car = Car("Mercedes")

    def add_body(self, body):
        self.car.body = body

    def add_engine(self, engine):
        """AMG 5.5L V8 biturbo"""
        self.car.engine = engine

    def add_tire(self, tire):
        self.car.tire = tire

    def assemble_car(self):
        return self.car

最後建造者模式中還會引入了一個指揮者類的角色,該類的作用主要是負責精確地控制產品的整個生成過程,根據使用者的不同需求返回不同的完整產品物件。

class Engineer(object):
    """指揮者
    """
    def __init__(self):
        self.builder = None

    def construct_car(self, body, engine, tire):
        self.builder = CarBuilder()
        self.builder.add_body(body)
        self.builder.add_engine(engine)
        self.builder.add_tire(tire)
        return self.builder.assemble_car()

只要把需求告訴指揮者,使用者就可以獲得一個產品的例項,如下所示:

engineer = Engineer()
car = engineer.construct_car(
        body="G63",
        engine="AMG 5.5L V8 biturbo",
        tire="Michelin 18inch")
print(car)

# Output
>Name: Mercedes
>Body: G63
>Engine: AMG 5.5L V8 biturbo
>Tire: Michelin 18inch

原型模式

原型模式(Prototype design pattern)的動機是為了讓使用者可以通過複製物件獲得一個物件的副本。此模式的出現是因為在C++和Java裡需要用此模式來更方便的拷貝物件,但在Python中要實現對一個物件的拷貝有更簡單辦法,我們就在這裡簡單的舉個例子:

#coding=utf-8
 class Foo(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "id: {}, x: {}, y: {}".format(id(self), self.x, self.y)

if __name__ == `__main__`:
    foo = Foo(1, 2)
    # 利用deepcopy獲得新物件
    import copy
    foo1 = copy.deepcopy(foo)
    foo1.x = 3
    foo1.y = 4
    print(foo, foo1)

    # 利用__class__方法獲得新
    foo2 = foo1.__class__(5, 6)
    print(foo, foo2)

# Output
>id: 4312696592, x: 1, y: 2 id: 4312696928, x: 3, y: 4
>id: 4312696592, x: 1, y: 2 id: 4312697096, x: 5, y: 6

上面我們用兩種原型方式實現了對Foo物件的拷貝,第一種是利用Python語言內建的deepcopy,第二種則用了更優雅的__class__方法。

結論

本文介紹的兩種模式在實際使用中並不常見,建造者模式應用在構造一些複雜的物件時,比如需要構建一個HTML物件,視窗物件或者遊戲中的建模等等,而原型模式則主要應用於一些需要備份狀態的物件或新建物件開銷過大的時候。

參考

[1]維基百科

相關文章