[Python设计模式] 第6章 衣服搭配系统——装饰模式

Posted ZH奶酪(张贺)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Python设计模式] 第6章 衣服搭配系统——装饰模式相关的知识,希望对你有一定的参考价值。

题目

设计一个控制台程序,可以给人搭配嘻哈风格(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章 衣服搭配系统——装饰模式的主要内容,如果未能解决你的问题,请参考以下文章

Python服务端工程师就业面试指导 完整版

JavaWeb项目开发案例精粹-第6章报价管理系统-001需求分析及设计

数据库原理与设计第一章知识点总结

系统分析与设计 复习

系统分析与设计 复习

软件建模——第6章 详细设计与实现