装饰模式(俄罗斯套娃?)

装饰模式:动态的给某些对象添加额外的功能

参考:

  • 简书 | 装饰模式

  • 博客园 | 简说设计模式——装饰模式

  • 博客园 | 装饰器模式 Decorator 结构型 设计模式 (十)

什么是装饰模式

装饰模式也叫装饰器模式,python中的装饰器就是这种模式的体现,对于一个类,如果要添加一个新功能,除了修改代码外(违反开闭原则),可以使用继承,但通过继承添加新功能并不适合所有场景,如

  1. 类不可见或不允许继承
  2. 需要对一批类似的兄弟类添加同一个新功能时,继承会产生大量的子类
  3. 希望新功能的添加和撤销是动态的

装饰模式中的对象包括:

  1. 装饰器(用来为被装饰对象动态添加新功能)

  2. 抽象被装饰对象(所有能被装饰对象的抽象)

  3. 被装饰对象

客户端如果希望给某个对象动态添加一个新功能,就可以把这个对象(被装饰对象)传递给装饰器,由装饰器实现新功能,并保存一个被装饰对象的引用,并返回给客户端一个装饰器对象,这样,被装饰对象原来的行为和属性并没有改变,甚至被装饰对象本身就没有改变,只是在外面套了一个壳子,新功能是这个壳子提供的。就像TCP/IP协议栈中,应用层的数据包到传输层通过加TCP或UDP首部来传输一样。

装饰模式优缺点

优点:

  1. 一个装饰器可以给多个不同的类动态添加新功能
  2. 新功能由装饰器实现,不需要修改被装饰对象,有一定的安全性
  3. 多个装饰器可以配合嵌套使用,以此实现更复杂的功能
  4. 新功能不影响原来的功能,添加和撤销都方便

缺点:

  1. 过多的装饰类可能使程序变得很复杂

  2. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

    作者:慵懒的阳光丶

适用场景

  1. 要添加的新功能与原有类关联不大时
  2. 新功能需要方便添加和撤销时
  3. 不能或不方便通过继承实现新功能时

比如卖烤冷面,最基本的就是面(抽象被装饰对象)具体的就是烤冷面(被装饰对象),然后可以往面里面加各种配料(抽象装饰器),如鸡蛋,辣条等(具体装饰器),由于不同配料的加入顺序对最后的烤冷面有影响,所以如果要用继承拓展“烤冷面”,那先加鸡蛋再加辣条和先加辣条再加鸡蛋就需要写两个子类,造成冗余重复,这种场景就适合适用装饰模式。

抽象被装饰对象

package pers.junebao.decorator_pattern;public abstract class Noodles {public String rawMaterial;  // 配料public abstract void sayWhoAmI();
}

具体的被装饰对象:

package pers.junebao.decorator_pattern;public class BakedColdNoodles extends Noodles {BakedColdNoodles() {this.rawMaterial = "面";  // 最原始的烤冷面,配料只有面}@Overridepublic void sayWhoAmI() {System.out.println("我是普通烤冷面!");}
}

抽象装饰器:

package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public abstract class Burden extends Noodles {public Noodles noodles;  // 装饰器中保留一份被装饰对象的引用,方便客户端使用public Burden(Noodles noodles) {this.noodles = noodles;}
}
  • 装饰器是为某一类对象提供装饰的(这里就是实现了Noodles 的类)

具体的装饰器类:

  • 加鸡蛋

    package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public class AddEggs extends Burden {public AddEggs(Noodles noodles) {super(noodles);this.rawMaterial = noodles.rawMaterial + ", 鸡蛋";}@Overridepublic void sayWhoAmI() {System.out.println("我是加了鸡蛋的烤冷面!!");}}
    
  • 加辣条

    package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public class AddSpicyStrips extends Burden{public AddSpicyStrips(Noodles noodles) {super(noodles);this.rawMaterial = noodles.rawMaterial + " ,辣条";}@Overridepublic void sayWhoAmI() {System.out.println("我是加了辣条的烤冷面!!");}
    }
    

客户端:

package pers.junebao.decorator_pattern;import pers.junebao.decorator_pattern.decorator.AddEggs;
import pers.junebao.decorator_pattern.decorator.AddSpicyStrips;public class Main {public static void main(String[] args) {Noodles bcn = new BakedColdNoodles();Noodles bcnAddEgg = new AddEggs(bcn);bcnAddEgg.sayWhoAmI();System.out.println(bcnAddEgg.rawMaterial);Noodles bcnEggSpicyS = new AddSpicyStrips(bcnAddEgg);bcnEggSpicyS.sayWhoAmI();System.out.println(bcnEggSpicyS.rawMaterial);}
}
/*
我是加了鸡蛋的烤冷面!!
面, 鸡蛋
我是加了辣条的烤冷面!!
面, 鸡蛋 ,辣条*/

这样如果想先加辣条在家鸡蛋,就可以使用AddSpicyStrips先装饰BakedColdNoodles,再用AddEggs装饰AddSpicyStrips。

GitHub | 完整代码

【设计模式 03】装饰模式——俄罗斯套娃?相关推荐

  1. 设计模式03:装饰模式

    系列总链接:https://blog.csdn.net/qq_22122811/article/details/112360387 参考:https://blog.csdn.net/hnust_xie ...

  2. 设计模式之装饰模式20170726

    结构型设计模式之装饰模式: 一.含义 动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活. 通俗来讲,装饰模式是对类的功能进行加强或减弱. 二.代码说明 1.主要有两个角 ...

  3. java设计模式之装饰模式_Java中的装饰器设计模式

    java设计模式之装饰模式 装饰器设计模式允许在运行时将附加职责或行为动态附加到对象. 它是一种结构模式,利用聚合来组合这些行为. 在本教程中,我们将学习实现装饰器模式. UML图: 让我们从装饰器模 ...

  4. 设计模式03 - 装饰者模式

    引入: 曾今以为继承能解决一切问题.在程序运行时发现,扩展的威力远大于编译时扩展的威力. 装饰者模式: 好处: 一旦知道装饰的技巧,你将能给你的(或别人的)对象一个新的责任,而不需要对底层class的 ...

  5. 大话设计模式之装饰模式(python实现)

    大话设计模式之装饰模式 使用场景 定义 装饰模式结构图 python实现装饰模式 代码结构图 优点 使用场景 建造过程不稳定,不确定.把所需的功能按照正确的顺序串联起来进行控制. 新加入的东西仅仅是为 ...

  6. 设计模式之装饰模式详解(附应用举例实现)

    文章目录 1 装饰模式介绍 2 装饰模式详解 2.1 装饰模式结构 2.2 装饰模式实现 2.3 装饰模式应用举例 3 透明装饰模式和半透明装饰模式 1 装饰模式介绍 在生活中,我们往往会给图片增加一 ...

  7. 设计模式之 装饰模式

    设计模式之 装饰模式 概述: 装饰模式(Decorator Pattern) 又叫装饰者模式:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也 ...

  8. 设计模式之三 装饰模式

    1.场景模拟 这样让想起了老李,我跟老李是很要好的哥们,当然他不像我还是光棍,所以他不光有友情还有爱情了,不过,就在最近几天他们吵架啦,什么原因?就不多说啦,总之身为男人的老李还是决定主动认错挽回女方 ...

  9. 设计模式之装饰模式(Decorator)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

最新文章

  1. 上传图片时出现Request 对象 错误 'ASP 0104 80004005'
  2. 转载 开发人员一定要加入收藏夹的网站
  3. 转: Linux下使用java -jar运行可执行jar包的正确方式
  4. .NET Compact Framework s60v3(在S60上运行Windows Mobile程序)
  5. boost::mp11::mp_assign相关用法的测试程序
  6. 算法题解:动态规划解0-1背包问题
  7. 【算法学习笔记】85.破环为链 序列DP 松弛+代价 SJTU OJ 1073 能量项链
  8. [转载]如何决定要使用多少点来做FFT?(转载)
  9. PHP MySQL 相关函数(上)
  10. oracle sqlplus ed,Uedit32与SQLPlus结合使用技巧-数据库专栏,ORACLE
  11. java中什么是线程安全_Java 多线程:什么是线程安全性
  12. jenkins + maven + nexus + [ svn 或 GitLab 或 GitHub ]
  13. 如何用公式编辑器打长等号
  14. 【Vue】postman汉化教程 保姆级教程 包教会
  15. blink usb无线网卡驱动 linux,lblink无线网卡驱动下载官方版_blink无线网卡驱动_blink无线网卡驱动_东坡下载...
  16. can总线一帧多少字节多少位_汽车CAN总线数据帧解析---汽车语言知多少
  17. 使用MATLAB Mapping工具箱创建和编辑地图
  18. 统计学考研笔记:季度指数
  19. 1038 Recover the Smallest Number (30 分)-字符串分段排序
  20. UI设计师未来职业规划

热门文章

  1. [基础篇]ESP32-RTOS-SDK教程(一)之Windows环境搭建
  2. [LeedCode]921. 使括号有效的最少添加
  3. C# 使用Conditional特性而不是#if条件编译
  4. 对session的理解
  5. PHP内核探索之变量(6)- 后续内核探索系列大纲备忘
  6. php CI 实战教程:如何去掉index.php目录
  7. 用c#写的一个局域网聊天客户端 类似小飞鸽
  8. 神马是线程?PHP对其具体的应用?应用在哪里?
  9. 遇到问题了 .net项目发布到iis6,没有权限访问!?
  10. 数据结构排序法之插入法