3.建立型模式

ThankCAT發表於2024-03-26

目錄
  • 1. 簡單工廠模式
  • 2. 工廠方法模式
  • 3. 抽象工廠模式
  • 4. 建造者模式
  • 5. 單例模式
  • 6. 建立型模式概述

1. 簡單工廠模式

簡單工廠模式不是23中設計模式中的,但是必須要知道。簡單工廠模式不直接向客戶端暴露物件建立的細節,而是透過一個工廠類來負責建立產品類的例項。簡單工程模式的角色有:工廠角色、抽象產品角色、具體產品角色,透過例子來加深理解:

from abc import ABCMeta, abstractmethod


# 抽象產品角色,以什麼樣的表現去使用
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 產品角色
class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei == True:
            print("花唄支付了{0}元!".format(money))
        else:
            print("支付寶餘額支付了{0}元!".format(money))

# 產品角色
class WechatPay(Payment):
    def pay(self, money):
        print("微信支付了%d元!" % (money))

# 工廠類角色
class PaymentFactory:
    def ctreate_payment(self, method):
        if method == 'Alipay':
            return Alipay()
        elif method == 'WechatPay':
            return WechatPay()
        elif method == 'HuabeiPay':
            return Alipay(use_huabei=True)
        else:
            raise TypeError('No such payment named %s' % method)

# 客戶端呼叫。不直接向客戶端暴露物件建立的實現細節,而是透過一個工廠類來負責建立產品類的例項
pf = PaymentFactory()
p = pf.ctreate_payment('HuabeiPay')
p.pay(100)
2. 工廠方法模式

簡單工廠模式只建立一個工廠類,當有新的產品時,需要修改工廠類程式碼。而 工廠方法模式的每個具體產品對應一個具體的工廠類,不需要修改工廠類程式碼,並且同時也能滿足隱藏物件建立的細節。但是工廠方法模式也是有缺點的,就是 每增加一個具體產品類,就必須增加一個相應的具體方法
工廠模式方法模式的概念是定義了一個用於建立物件的介面(工廠介面),讓子類決定例項化那一個產品類。角色有抽象工廠角色、具體工廠角色、抽象產品角色和具體產品角色。透過例子來加深理解,每個具體產品對應一個具體的工廠類:

from abc import ABCMeta, abstractmethod

# 抽象產品角色
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 具體產品角色
class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei == True:
            print("花唄支付了{0}元!".format(money))
        else:
            print("支付寶餘額支付了{0}元!".format(money))

class WechatPay(Payment):
    def pay(self, money):
        print("微信支付了%d元!" % (money))

# 抽象工廠角色
class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass

# 具體工廠角色
class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

class WechatPayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

class HuabeiFactory(PaymentFactory):
    def create_payment(self):
        return Alipay(use_huabei=True)

hfp = HuabeiFactory().create_payment()
hfp.pay(100)  # 花唄支付了100元!

缺點是每增加一個具體產品類,就必須增加一個相應的具體方法:

from abc import ABCMeta, abstractmethod

class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei == True:
            print("花唄支付了{0}元!".format(money))
        else:
            print("支付寶餘額支付了{0}元!".format(money))

class WechatPay(Payment):
    def pay(self, money):
        print("微信支付了%d元!" % (money))

class BankPay(Payment):
    def pay(self, money):
        print("銀行支付了%d元!" % (money))

# 建立產品的工廠類的介面
class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass

# 工廠類
class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

# 工廠類
class WechatPayPayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

# 工廠類
class HuabeiPayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay(use_huabei=True)

# 新增加銀行支付的工廠類
class BankPayFactory(PaymentFactory):
    def create_payment(self):
        return BankPay()

bfp = BankPayFactory().create_payment()
bfp.pay(100)  # 銀行支付了100元!
3. 抽象工廠模式

抽象工廠模式:定義一個工廠類的介面讓工廠子類來建立一系列相關或者相互依賴的物件。相比工廠方法模式,抽象工廠模式中的每一個具體工廠都生產一套產品。下面是生產廠商生產一部手機的例子:生產一部手機如果說只需要手機殼、CPU和作業系統這三個類物件,其中每個類物件都有不同的種類。對每個具體工廠,分別生產一部手機需要的三個物件。透過例子來加深理解:

from abc import ABCMeta, abstractmethod

# ------抽象的產品------
class PhoneShell(metaclass=ABCMeta):
    @abstractmethod
    def show_shell(self):
        pass

class PhoneCPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass

class PhoneOS(metaclass=ABCMeta):
    @abstractmethod
    def show_os(self):
        pass
        
# ------具體的產品------
class SmallShell(PhoneShell):
    def show_shell(self):
        print('普通手機小手機殼')

class BigShell(PhoneShell):
    def show_shell(self):
        print('普通手機大手機殼')

class AppleShell(PhoneShell):
    def show_shell(self):
        print('蘋果手機殼')

class SnapDragonCPU(PhoneCPU):
    def show_cpu(self):
        print('驍龍CPU')

class HuaweiCPU(PhoneCPU):
    def show_cpu(self):
        print('化為CPU')

class AppleCPU(PhoneCPU):
    def show_cpu(self):
        print('蘋果CPU')

class AndroidOS(PhoneOS):
    def show_os(self):
        print('IOS系統')

class AppleOS(PhoneOS):
    def show_os(self):
        print('安卓系統')

# ------抽象的工廠------
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass

    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass

# ------具體的工廠------
class HuaweiFactory(PhoneFactory):
    def make_shell(self):
        return SmallShell()

    def make_cpu(self):
        return HuaweiCPU()

    def make_os(self):
        return AndroidOS()

class AppleFactory(PhoneFactory):
    def make_shell(self):
        return AppleShell()

    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return AppleOS()

# ------客戶端------
class Phone:
    def __init__(self, shell, cpu, os):
        self.shell = shell
        self.cpu = cpu
        self.os = os

    def show_info(self):
        print('手機資訊:')
        self.shell.show_shell()
        self.cpu.show_cpu()
        self.os.show_os()

def make_phone(factory):
    shell = factory.make_shell()
    cpu = factory.make_cpu()
    os = factory.make_os()
    return Phone(shell, cpu, os)

p = make_phone(HuaweiFactory())
p.show_info()
"""
手機資訊:
普通手機小手機殼
化為CPU
IOS系統
"""

抽象工廠模式的角色有:抽象工廠角色、具體工廠角色、抽象產品角色、具體產品角色和客戶端。抽象工廠模式的優點是:將客戶端和類的具體實現相分離;每個工廠建立了一個完整的產品系列,使得易於交換產品系列;有利於產品的一致性,即產品之間的約束關係。缺點是:難以支援新種類抽象產品

4. 建造者模式

建造者模式是將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。角色有抽象建立者、具體建立者、指揮者和產品。建造者模式與抽象工廠模式相似,也用來建立複雜的物件。主要區別是 建造者模式著重一步步構造一個複雜物件(控制順序)。而抽象工廠模式著重於多個系列的產品物件,寫個例子來加強理解:

from abc import ABCMeta, abstractmethod

# ------產品------
class Player:
    def __init__(self, face=None, body=None, arms=None, legs=None):
        self.face = face
        self.body = body
        self.arms = arms
        self.legs = legs

    def __str__(self):
        return '%s,%s,%s,%s' % (self.face, self.body, self.arms, self.legs)

# ------抽象建造者------
class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def build_arms(self):
        pass

    @abstractmethod
    def build_legs(self):
        pass

# ------具體建造者,隱藏了一個產品的內部結構------
class GirlBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()

    def build_face(self):
        self.player.face = '漂亮的臉蛋'

    def build_body(self):
        self.player.body = '苗條的身材'

    def build_arms(self):
        self.player.arms = '細細的胳膊'

    def build_legs(self):
        self.player.legs = '大長腿'

# ------具體建造者,表示程式碼------
class MonsterBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()

    def build_face(self):
        self.player.face = '綠臉'

    def build_body(self):
        self.player.body = '魁梧的身體'

    def build_arms(self):
        self.player.arms = '粗壯的胳膊'

    def build_legs(self):
        self.player.legs = '粗壯的大腿'

# ------指揮者,構造程式碼(構造程式碼和表示程式碼分開),可以對構造過程進行更加精細地控制------
class PlayerDirectory():
    def builder_player(self, builder):
        """
        隱藏了裝配過程
        :param builder:
        :return:
        """
        builder.build_face()
        builder.build_body()
        builder.build_arms()
        builder.build_legs()
        return builder.player

# ------客戶端------
builder = GirlBuilder()
director = PlayerDirectory()
p = director.builder_player(builder)
print(p)  # 漂亮的臉蛋,苗條的身材,細細的胳膊,大長腿
5. 單例模式

單例模式保證一個類只有一個例項,並提供一個訪問它的全域性訪問點。優點是對唯一例項的受控訪問(只有一個例項),單例相當於全域性變數,但防止了名稱空間被汙染(變數命名不會有衝突)。寫個例子來加深理解:

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

class MyClass(Singleton):
    def __init__(self, a):
        self.a = a

ms1 = MyClass(1)
ms2 = MyClass(2)
print(ms1.a, ms2.a)
print(id(ms1), id(ms2))
"""
2 2
139843914173312 139843914173312
"""

如果例項只出現一次,如日誌系統中只需要建立一個日誌物件(否則兩個日誌物件同時操作一個檔案就會造成操作衝突);資料庫連線池只需要建立一個物件來運算元據庫(否則增加系統開銷,浪費系統資源);作業系統只需要建立一個檔案系統物件來操作檔案系統。

6. 建立型模式概述

抽象工廠模式和建造者模式相比於簡單工廠模式和工廠方法模式而言更加靈活也更加複雜。通常情況下,軟體設計以簡單工廠模式或工廠方法模式開始,當發現設計需要更大的靈活性的時候,則向更加複雜的設計模式演化。

相關文章