1. 程式人生 > >[Python設計模式] 第6章 衣服搭配系統——裝飾模式

[Python設計模式] 第6章 衣服搭配系統——裝飾模式

!= orb 定義 use bstr 單獨 name 代碼 服飾

題目

設計一個控制臺程序,可以給人搭配嘻哈風格(T恤,垮褲,運動鞋)或白領風格(西裝,領帶,皮鞋)的衣服並展示,類似QQ秀那樣的。

基礎版本

class Person():
    
    def __init__(self, name):
        self.name = name
    
    def wear_T_shirts(self):
        print("T恤")
    
    def wear_big_trouser(self):
        print("垮褲")
        
    def wear_sneakers(self):
        print("運動鞋")
    
    def wear_suit(self):
        print("西裝")
        
    def wear_tie(self):
        print("領帶")
        
    def wear_leather_shoes(self):
        print("皮鞋")
    
    def show(self):
        print("裝扮的{}".format(self.name))

客戶端代碼

def main():
    hezhang = Person("張賀")
    print("第一種裝扮")
    hezhang.wear_T_shirts()
    hezhang.wear_big_trouser()
    hezhang.wear_sneakers()
    hezhang.show()
    
    print("第二種裝扮")
    hezhang.wear_suit()
    hezhang.wear_tie()
    hezhang.wear_leather_shoes()
    hezhang.show()

main()
第一種裝扮
T恤
垮褲
運動鞋
裝扮的張賀
第二種裝扮
西裝
領帶
皮鞋
裝扮的張賀

點評

  • 僅實現了基本功能
  • 如果添加“超人”裝扮,需要如何做?需要在Person類中改代碼;
  • 如果Person類除了穿衣服,還要支持吃飯,睡覺等功能,需要如何做?需要在Person類中改代碼;
  • 綜上,需要把“服飾”類和“人”類分離。

改進版本1.0——人衣分離

class Person():
    
    def __init__(self, name):
        self.name = name
    
    def show(self):
        print("裝扮的{}".format(self.name))

from abc import ABCMeta, abstractmethod


class Finery(metaclass=ABCMeta):
    
    @abstractmethod
    def show(self):
        pass
    
class TShirts(Finery):
    
    def show(self):
        print("T恤")

class BigTrouser(Finery):
    
    def show(self):
        print("垮褲")
        
class Sneakers(Finery):
    
    def show(self):
        print("運動鞋")
        
class Suit(Finery):
    
    def show(self):
        print("西裝")
        
class Tie(Finery):
    
    def show(self):
        print("領帶")
        
class LeatherShoes(Finery):
    
    def show(self):
        print("皮鞋")

客戶端代碼

def main():
    hezhang = Person("張賀")
    print("第一種裝扮")
    t_shirts = TShirts()
    big_trouser = BigTrouser()
    sneakers = Sneakers()
    
    t_shirts.show()
    big_trouser.show()
    sneakers.show()
    hezhang.show()
    
    print("第二種裝扮")
    suit = Suit()
    tie = Tie()
    leather_shoes = LeatherShoes()
    suit.show()
    tie.show()
    leather_shoes.show()
    hezhang.show()

main()
第一種裝扮
T恤
垮褲
運動鞋
裝扮的張賀
第二種裝扮
西裝
領帶
皮鞋
裝扮的張賀

點評

分析以下代碼:

    hezhang = Person("張賀")
    t_shirts = TShirts()
    big_trouser = BigTrouser()
    sneakers = Sneakers()
    
    t_shirts.show()
    big_trouser.show()
    sneakers.show()
    hezhang.show()

用自然語言描述就是:

  • 先實例化出hezhang這個人類,準確的說,是沒有穿衣服的人類;
  • 再實例化並穿上出各種衣服,T恤,垮褲,運動鞋等;
  • 再展示出來hezhang

但是服飾和人之間好像沒有任何關系,那麽如何用代碼表示:

  • 實例化沒穿衣服的人類
  • 為沒穿衣服的人類穿上T恤
  • 為穿著T恤的人類穿上垮褲
  • 為穿著T恤,垮褲的人類穿上運動鞋

這需要用到裝飾模式。

裝飾模式

裝飾模式,為了動態的給一個對象添加一些額外的職責,就增加功能而言,裝飾模式比生成子類更為靈活[DP]。

裝飾模式有以下幾個主要組成部分:

  • 組件類Component:定義一個對象接口, 可以給這些對象動態的添加職責;
  • 具體組件類ConcretComponent:定義了一個具體對象,也可以給這個對象添加一些職責;
  • 裝飾類Decorator:裝飾抽象類,繼承Component,從外類來擴展Component類的功能,對於Component而言,無需知道Decorator的存在;
  • 具體裝飾類ConcretDecorator:具體裝飾類,為Component添加職責

用代碼表示:

from abc import ABCMeta, abstractmethod


class Component(metaclass=ABCMeta):
    """
    組件類Component:定義一個對象接口, 可以給這些對象動態的添加職責
    """
    @abstractmethod
    def operation(self):
        pass
    
    
class ConcreteComponent(Component):
    """
    具體組件類ConcretComponent:定義了一個具體對象,也可以給這個對象添加一些職責
    """
    def operation(self):
        print("具體組件的操作")
      
    
class Decorator(Component):
    """
    裝飾類Decorator:裝飾抽象類,繼承Component,從外類來擴展Component類的功能,對於Component而言,無需知道Decorator的存在;
    """
    def __init__(self):
        self.component = None
        
    def set_component(self, component):
        self.component = component
    
    def operation(self):
        if self.component != None:
            self.component.operation()
            
            
class ConcreteDecratorA(Decorator):
    """
    具體裝飾類ConcretDecorator:具體裝飾類,為Component添加職責
    """
    def __init__(self):
        self.added_operation = "A:具體裝飾類A獨有操作"
        
    def operation(self):
        super().operation()
        print(self.added_operation)
        print("A:具體裝飾對象A的操作")
        
        
class ConcreteDecratorB(Decorator):
    """
    具體裝飾類ConcretDecorator:具體裝飾類,為Component添加職責
    """
    def __init__(self):
        self.added_operation = "B:具體裝飾類B獨有操作"
        
    def operation(self):
        super().operation()
        print(self.added_operation)
        print("B:具體裝飾對象B的操作")
def main():
    component = ConcreteComponent()
    decorator_a = ConcreteDecratorA()
    decorator_b = ConcreteDecratorB()
    
    decorator_a.set_component(component)
    decorator_b.set_component(decorator_a)
    decorator_b.operation()
    
main()
具體組件的操作
A:具體裝飾類A獨有操作
A:具體裝飾對象A的操作
B:具體裝飾類B獨有操作
B:具體裝飾對象B的操作

改進版本2.0——裝飾模式

from abc import ABCMeta,abstractmethod


class Person():
    """
    人物類(組件類)
    """
    def __init__(self, name):
        self.name = name
    
    def show(self):
        print("裝扮的{}".format(self.name))
    
    
class Finery(Person):
    """
    服飾類(裝飾類)
    """
    def __init__(self):
        self.component = None
    
    def decorate(self, component):
        self.component = component
        
    
    def show(self):
        if self.component != None:
            self.component.show()
            

class TShirts(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("T恤")
        super().show()

class BigTrouser(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("垮褲")
        super().show()
        
        
class Sneakers(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("運動鞋")
        super().show()
        
class Suit(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("西裝")
        super().show()
        
class Tie(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("領帶")
        super().show()
        
class LeatherShoes(Finery):
    """
    具體裝飾類
    """
    def show(self):
        print("皮鞋")
        super().show()

客戶端代碼

def main():
    hezhang = Person("張賀")
    t_shirts = TShirts()
    big_trouser = BigTrouser()
    sneakers = Sneakers()
    
    t_shirts.decorate(hezhang)
    big_trouser.decorate(t_shirts)
    sneakers.decorate(big_trouser)
    sneakers.show()
    
main()
運動鞋
垮褲
T恤
裝扮的張賀

點評

上述客戶端代碼可以用自然語言描述為:

  • 實例化沒穿衣服的人類
  • 為沒穿衣服的人類穿上T恤
  • 為穿著T恤的人類穿上垮褲
  • 為穿著T恤,垮褲的人類穿上運動鞋

所以,裝飾模型是為已有功能動態的添加更多功能的一種方式,它把每個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,因此,當需要執行特殊行為時,客戶端代碼可以在運行時根據需要有選擇的,按順序的使用裝飾功能包裝對象。

裝飾模式的優點在於,把類中的裝飾功能從類中搬移出去,這樣可以簡化原有的類,有效的把類的核心職責裝飾功能區分開了。而且可以去除相關類中重復的裝飾邏輯,即一個裝飾功能可以給多個不同的類使用。

[Python設計模式] 第6章 衣服搭配系統——裝飾模式