• 设计模式- 装饰器模式(Decorator Pattern)结构|原理|优缺点|场景|示例


                                        设计模式(分类)        设计模式(六大原则)   

        创建型(5种)        工厂方法         抽象工厂模式        单例模式        建造者模式        原型模式

        结构型(7种)        适配器模式        装饰器模式        代理模式        ​​​​​​外观模式      桥接模式        组合模式       享元模式

        行为型(11种)        策略模式        模板方法模式        观察者模式        迭代器模式        责任链模式        命令模式

                                       备忘录模式          状态模式          访问者模式        中介者模式    


    装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在运行时动态地给对象添加新的职责(功能)或改变其原有行为。装饰器模式通过创建一个装饰器类,该类包装(持有)原始对象,并在保持原始对象接口不变的前提下,通过代理或继承的方式添加新的功能。装饰器模式可以提供比继承更灵活的扩展方式,因为它可以在不修改原有类的情况下,为对象添加新功能,并且可以叠加多个装饰器以实现多重增强。

    模式结构

    装饰器模式通常包含以下角色:

    1. 组件接口(Component):定义了基础功能的接口,所有具体组件和装饰器都要实现这个接口,以便于保持接口的一致性。

    2. 具体组件(Concrete Component):实现了组件接口,是需要被装饰的基础对象。

    3. 装饰器(Decorator):实现了组件接口,并持有一个组件接口类型的引用,用于存储被装饰的对象。装饰器可以在实现组件接口方法的基础上,添加新的职责或修改原有行为。

    4. 具体装饰器(Concrete Decorators):继承自装饰器类,为具体组件添加新的职责或修改其行为。具体装饰器可以在构造函数中接收被装饰的对象,并在实现组件接口方法时调用被装饰对象的对应方法。

    工作原理

    • 客户端:创建具体组件对象,并根据需要通过装饰器对其进行装饰。客户端始终面向组件接口编程,无需关心对象是否被装饰以及如何装饰。
    • 装饰器:持有一个组件接口类型的引用,用于存储被装饰的对象。装饰器在实现组件接口方法时,可以调用被装饰对象的对应方法,并在此基础上添加新功能或修改原有行为。
    • 具体装饰器:在构造函数中接收被装饰的对象,并在实现组件接口方法时调用被装饰对象的对应方法,同时添加新的职责或修改原有行为。

    优缺点

    优点
    • 开放封闭原则:装饰器模式遵循“开闭原则”,允许在不修改原有类的情况下,动态地为对象添加新功能,增强了系统的可扩展性。
    • 灵活性:可以使用多个装饰器对同一个对象进行多次装饰,从而实现不同组合的增强功能。
    • 透明性:装饰后的对象与未装饰的对象在对外接口上保持一致,客户端无需关心对象是否被装饰以及如何装饰,只需面向组件接口编程。
    缺点
    • 过度使用可能导致类层次过深:如果过度使用装饰器模式,可能会导致类的层次过深,增加系统的复杂性。
    • 不易于理解:对于不熟悉装饰器模式的开发人员来说,可能需要花费更多时间理解装饰器的实现逻辑。

    适用场景

    • 需要为对象动态添加新功能,且新功能与原有功能可独立变化:装饰器模式可以在运行时为对象添加新功能,新功能与原有功能通过装饰器类进行封装,二者可以独立变化。
    • 需要保持类的开放封闭原则,避免修改已有代码:装饰器模式可以在不修改原有类的情况下,通过创建装饰器类为对象添加新功能,符合开放封闭原则。
    • 需要为对象提供多种可选的附加功能,且这些功能可以自由组合:通过使用多个装饰器对同一对象进行装饰,可以实现不同组合的增强功能。

    代码示例(以Java为例)

    1. // 组件接口
    2. interface Coffee {
    3. double getCost();
    4. String getDescription();
    5. }
    6. // 具体组件
    7. class SimpleCoffee implements Coffee {
    8. @Override
    9. public double getCost() {
    10. return 10.0;
    11. }
    12. @Override
    13. public String getDescription() {
    14. return "Simple coffee";
    15. }
    16. }
    17. // 装饰器
    18. abstract class CoffeeDecorator implements Coffee {
    19. protected Coffee decoratedCoffee;
    20. public CoffeeDecorator(Coffee decoratedCoffee) {
    21. this.decoratedCoffee = decoratedCoffee;
    22. }
    23. @Override
    24. public double getCost() {
    25. return decoratedCoffee.getCost();
    26. }
    27. @Override
    28. public String getDescription() {
    29. return decoratedCoffee.getDescription();
    30. }
    31. }
    32. // 具体装饰器
    33. class MilkCoffee extends CoffeeDecorator {
    34. public MilkCoffee(Coffee decoratedCoffee) {
    35. super(decoratedCoffee);
    36. }
    37. @Override
    38. public double getCost() {
    39. return super.getCost() + 2.0;
    40. }
    41. @Override
    42. public String getDescription() {
    43. return super.getDescription() + ", with milk";
    44. }
    45. }
    46. class VanillaCoffee extends CoffeeDecorator {
    47. public VanillaCoffee(Coffee decoratedCoffee) {
    48. super(decoratedCoffee);
    49. }
    50. @Override
    51. public double getCost() {
    52. return super.getCost() + 3.0;
    53. }
    54. @Override
    55. public String getDescription() {
    56. return super.getDescription() + ", with vanilla";
    57. }
    58. }
    59. // 客户端代码
    60. public class Client {
    61. public static void main(String[] args) {
    62. Coffee simpleCoffee = new SimpleCoffee();
    63. System.out.println(simpleCoffee.getDescription() + " costs " + simpleCoffee.getCost());
    64. // 输出:Simple coffee costs 10.0
    65. Coffee milkCoffee = new MilkCoffee(simpleCoffee);
    66. System.out.println(milkCoffee.getDescription() + " costs " + milkCoffee.getCost());
    67. // 输出:Simple coffee, with milk costs 12.0
    68. Coffee vanillaMilkCoffee = new VanillaCoffee(milkCoffee);
    69. System.out.println(vanillaMilkCoffee.getDescription() + " costs " + vanillaMilkCoffee.getCost());
    70. // 输出:Simple coffee, with milk, with vanilla costs 15.0
    71. }
    72. }

     在这个Java示例中:

    • Coffee接口作为组件接口,定义了获取咖啡价格和描述的方法。
    • SimpleCoffee类是需要被装饰的具体组件,实现了基础的咖啡功能。
    • CoffeeDecorator类作为装饰器,实现了Coffee接口,并持有一个Coffee类型的引用,用于存储被装饰的对象。装饰器类实现了getCost()getDescription()方法,但并未添加新功能,主要是为了方便具体装饰器类的继承。
    • MilkCoffeeVanillaCoffee类是具体装饰器,分别继承自CoffeeDecorator,并在构造函数中接收被装饰的对象。它们在实现getCost()getDescription()方法时,调用了被装饰对象的对应方法,并在此基础上添加了新功能(牛奶和香草)的费用和描述。
    • 客户端代码创建SimpleCoffee对象,并根据需要通过装饰器对其进行装饰,最终得到添加了牛奶和香草的咖啡。客户端始终面向Coffee接口编程,无需关心对象是否被装饰以及如何装饰。

    代码示例(以Python为例)

    1. # 组件接口
    2. class Coffee:
    3. def get_cost(self):
    4. raise NotImplementedError("Subclasses must implement this method")
    5. def get_description(self):
    6. raise NotImplementedError("Subclasses must implement this method")
    7. # 具体组件
    8. class SimpleCoffee(Coffee):
    9. def __init__(self):
    10. self.cost = 10
    11. self.description = "Simple coffee"
    12. def get_cost(self):
    13. return self.cost
    14. def get_description(self):
    15. return self.description
    16. # 装饰器
    17. class CoffeeDecorator(Coffee):
    18. def __init__(self, decorated_coffee: Coffee):
    19. self.decorated_coffee = decorated_coffee
    20. def get_cost(self):
    21. return self.decorated_coffee.get_cost()
    22. def get_description(self):
    23. return self.decorated_coffee.get_description()
    24. # 具体装饰器
    25. class MilkCoffee(CoffeeDecorator):
    26. def __init__(self, decorated_coffee: Coffee):
    27. super().__init__(decorated_coffee)
    28. self.cost = decorated_coffee.get_cost() + 2
    29. self.description = decorated_coffee.get_description() + ", with milk"
    30. class VanillaCoffee(CoffeeDecorator):
    31. def __init__(self, decorated_coffee: Coffee):
    32. super().__init__(decorated_coffee)
    33. self.cost = decorated_coffee.get_cost() + 3
    34. self.description = decorated_coffee.get_description() + ", with vanilla"
    35. # 客户端代码
    36. def main():
    37. simple_coffee = SimpleCoffee()
    38. print(simple_coffee.get_description(), "costs", simple_coffee.get_cost()) # 输出:Simple coffee costs 10
    39. milk_coffee = MilkCoffee(simple_coffee)
    40. print(milk_coffee.get_description(), "costs", milk_coffee.get_cost()) # 输出:Simple coffee, with milk costs 12
    41. vanilla_milk_coffee = VanillaCoffee(milk_coffee)
    42. print(vanilla_milk_coffee.get_description(), "costs", vanilla_milk_coffee.get_cost()) # 输出:Simple coffee, with milk, with vanilla costs 15
    43. if __name__ == "__main__":
    44. main()

    在这个Python示例中:

    • Coffee类作为组件接口,定义了获取咖啡价格和描述的接口。
    • SimpleCoffee类是需要被装饰的具体组件,实现了基础的咖啡功能。
    • CoffeeDecorator类作为装饰器,实现了组件接口,并持有一个Coffee类型的引用,用于存储被装饰的对象。装饰器类实现了get_cost()get_description()方法,但并未添加新功能,主要是为了方便具体装饰器类的继承。
    • MilkCoffeeVanillaCoffee类是具体装饰器,分别继承自CoffeeDecorator,并在构造函数中接收被装饰的对象。它们在实现get_cost()get_description()方法时,调用了被装饰对象的对应方法,并在此基础上添加了新功能(牛奶和香草)的费用和描述。
    • 客户端代码创建SimpleCoffee对象,并根据需要通过装饰器对其进行装饰,最终得到添加了牛奶和香草的咖啡。客户端始终面向Coffee接口编程,无需关心对象是否被装饰以及如何装饰。
  • 相关阅读:
    【paper】Cam2BEV论文浅析
    docker 安装minio
    2022年8月叙利亚再次因国考全国断网
    python装饰器原理梳理
    机器视觉双目测宽仪 高温钢板实时无滞后检测
    剑指offer 刷题速览
    spring boot 中的异步@Async
    鸿蒙应用模型开发-更新SDK后报错解决
    缓存读写淘汰算法W-TinyLFU算法
    AI创作专家,免费的AI创作专家工具
  • 原文地址:https://blog.csdn.net/piaomiao_/article/details/138036980