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


    github地址:https://github.com/cheesezh/python_design_patterns

    题目

    设计一个控制台程序,可以给人搭配嘻哈风格(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恤,垮裤的人类穿上运动鞋

    所以,装饰模型是为已有功能动态的添加更多功能的一种方式,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户端代码可以在运行时根据需要有选择的,按顺序的使用装饰功能包装对象。

    装饰模式的优点在于,把类中的装饰功能从类中搬移出去,这样可以简化原有的类,有效的把类的核心职责装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑,即一个装饰功能可以给多个不同的类使用。

  • 相关阅读:
    Jquery 图片走马灯效果原理
    jquery实现跑马灯效果(一)
    jQuery实现网页放大镜功能
    JavaScript仿淘宝实现放大镜效果的实例
    jquery实现放大镜简单方法
    jQuery实现放大镜效果
    小白jquery横向菜单弹出菜单制作
    转载 Log4j2在WEB项目中配置
    Struts2关于命名空间的例子
    转载关于struts命名空间的一则报警
  • 原文地址:https://www.cnblogs.com/CheeseZH/p/9374617.html
Copyright © 2020-2023  润新知