-
设计模式-装饰模式
结构图解释:
Component 可以是接口,也可以是抽象类,目的是指明Operation(),也就是规范要做什么。
ConcreteComponent 一个类,继承或者实现Component。是被装饰的代表,例如饭,奶茶。
Decorator类 装饰类,内部一定有Component或者ConcreteComponent的属性,表明用于装饰谁(扩展谁)。
ConcreteDecoratorA,ConcreteDecoratorB 我理解是各种装饰物(扩展)
如果只有一个ConcreteComponent而没有抽象的Component,那么Decorator类可以是ConcreteComponent的子类
何谓装饰模式?
例如,我现在有碗白饭,这饭上可以放土豆丝,放白菜,放豆干,放鸭腿,这就是鸭腿饭了。
那我放土豆丝,放白菜,放鸡腿,放豆干,这就是鸡腿饭了。
放不同的配菜,就是不同的套餐,如果我现在的菜单上有下述几种套餐:
鸡腿饭(鸡腿+青菜+香干)
肉丝饭(肉丝+青菜+香干)
大排饭(大排+青菜+香干)
鸭腿饭(鸭腿+青菜+香干)
东坡肉饭(东坡+青菜+香干)
要实现这几种饭
先用最容易想到的方式实现,每种套餐创建一个类,那么就有鸡腿饭类,肉丝饭类,大排饭类...
如果我现在鸡腿饭+一个大排你怎么办?
难道在创建一个鸡腿饭+一个大排的类?
那如果我要再加一个东坡肉呢?再加一个鸭腿呢?(这真有钱啊)
现在就发现我们这个实现方式就并不合适了。
我们先来分析一下,不同套餐其实就是不同的配菜加米饭对不对,像不像再给米饭的基础上一直叠加东西。
用装饰模式代码实现如下
/** * SX小吃 我这里卖 * 鸡腿饭(鸡腿+青菜+香干) * 肉丝饭(肉丝+青菜+香干) * 大排饭(大排+青菜+香干) * 鸭腿饭(鸭腿+青菜+香干) * 东坡肉饭(东坡+青菜+香干) * @author wrj * @description * @Date 2021/12/1 2:37 下午 */ abstract class Food { public abstract void has(); } //米饭 class Rice extends Food{ @Override public void has() { System.out.println("有米饭"); } } //装饰类 abstract class FoodDecorator extends Food{ public Food food; public void addFood(Food food){ this.food = food; } @Override public void has() { food.has(); } } //鸡腿 class Drumstick extends FoodDecorator{ @Override public void has() { System.out.println("有鸡腿"); super.has(); } } //肉丝 class ShreddedMeat extends FoodDecorator{ @Override public void has() { System.out.println("有肉丝"); super.has(); } } //大排 class PorkRibs extends FoodDecorator{ @Override public void has() { System.out.println("有大排"); super.has(); } } //青菜 class Vegetable extends FoodDecorator{ @Override public void has() { System.out.println("有青菜"); super.has(); } } //豆干 class DriedBeanCurd extends FoodDecorator{ @Override public void has() { System.out.println("有豆干"); super.has(); } } public class SXFood { //变量写中文为了方便理解 并不标准 public static void main(String[] args) { //标准鸡腿饭的构建过程 System.out.println("鸡腿饭:\r\n"); Rice 米饭 = new Rice(); DriedBeanCurd 豆干 = new DriedBeanCurd(); Vegetable 青菜 = new Vegetable(); Drumstick 鸡腿 = new Drumstick(); 鸡腿.addFood(青菜); 青菜.addFood(豆干); 豆干.addFood(米饭); 鸡腿.has(); //特殊需求 鸡腿饭+大排 System.out.println("鸡腿饭+大排:\r\n"); Rice 米饭1 = new Rice(); DriedBeanCurd 豆干1 = new DriedBeanCurd(); Vegetable 青菜1 = new Vegetable(); Drumstick 鸡腿1 = new Drumstick(); PorkRibs 大排 = new PorkRibs(); 鸡腿1.addFood(大排); 大排.addFood(青菜1); 青菜1.addFood(豆干1); 豆干1.addFood(米饭1); 鸡腿1.has(); } }
最后输出:
装饰的过程感觉像构建一个链表的过程
可以看到 装饰的过程类似于构建一个链表的过程,每个链表的节点调用has方法时都会去调用super的has从而调用下一个节点的has直至最后一个节点
这种场景就适合用装饰模式了。回过头来再看装饰模式的概念:
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
上面的鸡腿饭+大排的场景就体现了动态添加的特性以及为什么比子类更灵活因为我们不用一直生成子类,我们可以任意加东西来实现功能
可以看到 不同的搭配最终组合成了不同的套餐,这样不管有什么奇葩的需求,都不用改类,只需要改装饰的内容和顺序即可。
这也体现了开闭原则,不用改变基础的类,只需要改变使用方法即可。
需要注意装饰的顺序,顺序地不同,产生的结果也是不同的。这点需要注意
总结:
装饰模式是为已有功能动态地添加更多功能的一种方式,当系统需要新功能时,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为。
在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要(参考鸡腿饭加一个大排的场景)。
装饰模式提供了一个非常好的解决办法,它把每个要装饰的功能放在单独的类中。并让这个类包装它所要装饰的对象。因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象。
优点:把类中的装饰功能从类中搬移出去,简化原有的类。有效地把类的核心职责和装饰功能区分开。
原文:https://www.cnblogs.com/randy123/p/15629710.html
最新更新
python爬虫及其可视化
使用python爬取豆瓣电影短评评论内容
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比