返回顶部

python-装饰器模式

源码地址:https://github.com/weilanhanf/PythonDesignPatterns

说明:

有时为了给某个对象而不是给整个类添加一个功能,使用继承机制是添加功能的一个有效途径,但是不够灵活,用户不能控制对组件加边框的方式和时机,并且会导致子类膨胀。一种较为灵活的方式就是将组件嵌入另一个对象中,这个嵌入的对象叫做装饰。

装饰模式:动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。以对客户透明的方式动态地给一个对象附加上更多的责任 可以在不需要创建更多子类的情况下,让对象的功能得以扩展

装饰模式分析

可以在不改变一个对象本身功能的基础上给对象增加额外的新行为 是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系 引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能

 

装饰模式的结构

装饰模式包含以下4个角色: Component(抽象构件) ConcreteComponent(具体构件) Decorator(抽象装饰类) ConcreteDecorator(具体装饰类)

实例:

#又提到了那个快餐点餐系统,不过今天我们只以其中的一个类作为主角:饮料类。首先,回忆下饮料类:
class Beverage():
    name = ""
    price = 0.0
    type = "BEVERAGE"
    def getPrice(self):
        return self.price
    def setPrice(self, price):
        self.price = price
    def getName(self):
        return self.name

class coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0

class milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0

#除了基本配置,快餐店卖可乐时,可以选择加冰,如果加冰的话,要在原价上加0.3元;
# 卖牛奶时,可以选择加糖,如果加糖的话,要原价上加0.5元。怎么解决这样的问题?
# 可以选择装饰器模式来解决这一类的问题。首先,定义装饰器类:
class drinkDecorator():
    def getName(self):
        pass
    def getPrice(self):
        pass

class iceDecorator(drinkDecorator):
    def __init__(self, beverage):
        self.beverage = beverage
    def getName(self):
        return self.beverage.getName() + " +ice"
    def getPrice(self):
        return self.beverage.getPrice() + 0.3

class sugarDecorator(drinkDecorator):
    def __init__(self, beverage):
        self.beverage = beverage
    def getName(self):
        return self.beverage.getName() + " +sugar"
    def getPrice(self):
        return self.beverage.getPrice() + 0.5

#构建好装饰器后,在具体的业务场景中,就可以与饮料类进行关联。以可乐+冰为例,示例业务场景如下:
if  __name__=="__main__":
    coke_cola=coke()
    print("Name:%s"%coke_cola.getName())
    print("Price:%s"%coke_cola.getPrice())
    ice_coke=iceDecorator(coke_cola)
    print("Name:%s" % ice_coke.getName())
    print("Price:%s" % ice_coke.getPrice())

 打印结果:

Name:coke
Price:4.0
Name:coke +ice
Price:4.3

模式优点

对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为 可以对一个对象进行多次装饰 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无须改变,符合开闭原则

模式缺点

使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能 比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐

模式适用环境

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式  

posted on 2018-06-02 23:41  weilanhanf  阅读(3496)  评论(0编辑  收藏  举报

导航