装饰模式

77 阅读3分钟

1. 装饰模式简介

装饰模式是一种结构型设计模式,允许你通过将对象放入包装对象中来为原始对象添加新的行为。

2. 详细介绍

当你希望在不改变现有代码结构的情况下动态地向对象添加新功能时,装饰模式是一个非常有用的工具。

2.1 模式结构

装饰模式包括四个核心角色:抽象组件(Component)、具体组件(ConcreteComponent)、抽象装饰器(Decorator)、具体装饰器(ConcreteDecorator)。

  • Component: 定义了对象的接口,可以附加行为。
  • ConcreteComponent: 实现了Component接口,并定义了原始对象的行为。
  • Decorator: 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
  • ConcreteDecorator: 向组件添加新的行为。

2.2 调用装饰模式相关对象的时序

  1. 客户端创建一个具体组件对象并将其传递给装饰器。
  2. 装饰器将具体组件包装在内,并且可以根据需要包装多次。
  3. 客户端使用最后返回的装饰对象,该对象具有所有添加的行为。

3. 装饰模式的优缺点以及使用场景

优点:

  • 允许你动态地向对象添加新功能,而无需改变其结构。
  • 可以将多个装饰器组合在一起,以增加功能的灵活性。

缺点:

  • 可能会产生大量的小型装饰器类,增加了代码的复杂性。

适用场景:

  • 当需要在不修改现有对象代码的情况下,动态地添加功能时。
  • 当需要动态地移除功能时。

4. 使用Python实现装饰模式:以对文件数据进行加密和压缩为例

4.1 UML图示

装饰模式.png

4.2 代码示例

class DataSource:
    def write_data(self, data):
        pass

    def read_data(self):
        pass

class DataSourceDecorator(DataSource):
    _wrappee = None

    def __init__(self, source):
        self._wrappee = source

    def write_data(self, data):
        self._wrappee.write_data(data)

    def read_data(self):
        return self._wrappee.read_data()

class EncryptionDecorator(DataSourceDecorator):
    def write_data(self, data):
        super().write_data(self._encrypt(data))

    def read_data(self):
        return self._decrypt(super().read_data())

    def _encrypt(self, data):
        return data + " [encrypted]"

    def _decrypt(self, data):
        return data.replace(" [encrypted]", "")

class CompressionDecorator(DataSourceDecorator):
    def write_data(self, data):
        super().write_data(self._compress(data))

    def read_data(self):
        return self._decompress(super().read_data())

    def _compress(self, data):
        return data + " [compressed]"

    def _decompress(self, data):
        return data.replace(" [compressed]", "")

# Example usage:
data_source = CompressionDecorator(EncryptionDecorator(DataSource()))
data_source.write_data("Data to be written")
print(data_source.read_data())

5. 简单练习:设计模式专题装饰模式】8-咖啡加糖

""" 
设计模式专题装饰模式】8-咖啡加糖
时间限制:1.000S  空间限制:256MB
题目描述
小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。 

请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。

输入描述
多行输入,每行包含两个数字。第一个数字表示咖啡的选择(1 表示黑咖啡,2 表示拿铁),第二个数字表示要添加的调料类型(1 表示牛奶,2 表示糖)。
输出描述
根据每行输入,输出制作咖啡的过程,包括咖啡类型和添加的调料。
输入示例
1 1
2 2
输出示例
Brewing Black Coffee
Adding Milk
Brewing Latte
Adding Sugar
"""


from abc import ABC, abstractmethod


class Coffee(ABC):
    @abstractmethod
    def brew(self):
        raise NotImplemented
        

class BlackCoffee(Coffee):
    def brew(self):
        print("Brewing Black Coffee")
        
        
class Latte(Coffee):
    def brew(self):
        print("Brewing Latte")
        
        
class Flavour(Coffee):
    def __init__(self, coffee: Coffee):
        self.coffee = coffee
        
    @abstractmethod
    def brew(self):
        raise NotImplemented
        
        
class Milk(Flavour):
    def __init__(self, coffee: Coffee):
        super().__init__(coffee)
        
    def brew(self):
        self.coffee.brew()
        print("Adding Milk")
        
        
class Sugar(Flavour):
    def __init__(self, coffee: Coffee):
        super().__init__(coffee)
    
    def brew(self):
        self.coffee.brew()
        print("Adding Sugar")
        
        
def client():
    while True:
        try:
            coffeeType, flavourType = input().split(" ")
            if coffeeType == "1":
                coffee = BlackCoffee()
            else:
                assert coffeeType == "2"
                coffee = Latte()
                
            if flavourType == "1":
                flavour = Milk(coffee)
            else:
                assert flavourType == "2"
                flavour = Sugar(coffee)
                
            flavour.brew()
            
        except EOFError:
            break
        
        
if __name__ == "__main__":
    client()

6. 参考文章