装饰者模式(十一)

news2025/2/8 20:30:03

请相信自己,请再次相信自己,请一定要相信自己

上一章简单介绍了桥接模式(十), 如果没有看过, 请观看上一章

一. 装饰者模式

引用 菜鸟教程里面的装饰者模式介绍: https://www.runoob.com/design-pattern/decorator-pattern.html

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。

这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

介绍

意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

主要解决: 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用: 在不想增加很多子类的情况下扩展类。

如何解决: 将具体功能职责划分,同时继承装饰者模式。

关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

应用实例:
1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。
在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

优点: 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点: 多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

注意事项: 可代替继承。

组成角色具体关系作用
ComponentDrink被装饰对象的基类给这些对象动态地添加职责
ConcreteComponentCoffee 和及子类 EluosiCoffee, SingleCoffee具体被装饰对象具体被装饰对象
DecoratorDecorator装饰者抽象类装饰者抽象类
ConcreteDecoratorBingDecorator, QiaoKeLiDecorator具体装饰者具体装饰者

image-20230614165054352

二. 装饰者模式

由 两部分组成,
一部分是基础种类, 另外一部分是配带信息,可用可无,也可以多次进行的。

这两部分,都需要继承一个总的抽象类。

有两部分拆分的, 一部分是主体的, 另外一部分是配带的。

定义一个 总的 抽象类

然后 主体均实现 这个抽象类

配带的部分 实现抽象类, 并依赖主体信息

二.一 基类 Drink

@Data
public abstract class Drink {
    private BigDecimal price;
    private String desc;

    // 子类进行实现
    public abstract BigDecimal cost();

}

二.二 被装饰的对象 Coffee

public class Coffee extends Drink{

    @Override
    public BigDecimal cost() {
        // 计算价格
      return super.getPrice();
    }
}

二.三 装饰对象 Coffee 的子类

有单纯的 俄罗斯咖啡,拿铁咖啡,原咖啡,杨枝咖啡

public class EluosiCoffee extends Coffee {

    public EluosiCoffee() {
        setDesc("俄罗斯咖啡");
        setPrice(new BigDecimal(15));
    }

}
public class NaTieCoffee extends Coffee {

    public NaTieCoffee() {
        setDesc("拿铁咖啡");
        setPrice(new BigDecimal(12));
    }

}

public class SingleCoffee extends Coffee {

    public SingleCoffee() {
        setDesc("原咖啡");
        setPrice(new BigDecimal(10));
    }

}
public class YangZhiCoffee extends Coffee {

    public YangZhiCoffee() {
        setDesc("杨枝咖啡");
        setPrice(new BigDecimal(15));
    }

}

二.四 装饰者抽象类 Decorator

public class Decorator extends Drink{
    private Drink drink ;
    public Decorator (Drink drink) {
        this.drink = drink;
    }

    @Override
    public BigDecimal cost() {
        // 之前的,加上现在的。
       return drink.cost().add(getPrice());
    }

    @Override
    public String getDesc() {
        return super.getDesc()+""+getPrice() +"&&" +drink.getDesc();
    }
}

二.五 装饰者子类

可以加 冰, 牛奶, 巧克力, 糖

public class BingDecorator extends Decorator{

    public BingDecorator(Drink drink) {
        super(drink);
        setPrice(new BigDecimal(0));
        setDesc("冰");
    }
}
public class MilkDecorator extends Decorator{

    public MilkDecorator(Drink drink) {
        super(drink);
        setPrice(new BigDecimal(2));
        setDesc("牛奶");
    }
}
public class QiaoKeLiDecorator extends Decorator{

    public QiaoKeLiDecorator(Drink drink) {
        super(drink);
        setPrice(new BigDecimal(3));
        setDesc("巧克力");
    }
}
public class TangDecorator extends Decorator{

    public TangDecorator(Drink drink) {
        super(drink);
        setPrice(new BigDecimal(0));
        setDesc("糖");
    }
}

二.六 客户端调用

@Test
    public void oneTest() {
        Drink drink = new SingleCoffee();
        log.info("单咖啡:{}",drink.cost());

        drink = new MilkDecorator(drink);

        drink = new TangDecorator(drink);

        log.info("加了牛奶和糖:{}", drink.cost());

        drink = new NaTieCoffee();

        log.info("拿铁:{}", drink.cost());

    }

image-20230614165744103

装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。

在这里应用继承并不是实现方法的复制,而是实现类型的匹配。

因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。

根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Decorator


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/646250.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是开源工作流平台?

在办公职场中,有没有一款软件是实现提质增效的平台?如果让办公实现流程化管理,引用什么平台产品较为合适?低代码开发平台是近些年较为流行的办公软件平台,可以有效管理数据资源,制作表格可视化操作更简便&a…

Qt Quick系列(6)—多风格UI页面

🚀作者:CAccept 🎂专栏:Qt Quick 文章目录 前言桌面版本的UI界面代码示例相关知识点 移动版风格的UI界面代码示例 嵌套页面代码示例相关知识点 并排页面代码示例相关知识点 前言 Qt Quick控件用于创建由标准化组件(…

OpenCV迭代去畸变undistortPoints 与vins的迭代不同 vins前端与imu预积分

OpenCV去畸变undistortPoints原理解析 不动点迭代法—单变量非线性方程近似根matlab求解 淦VINS-MONO源码 03–openCV与VINS中去畸变方法的不同 这里用的方法和openCV不同,假设现在求A点的去畸变坐标,那么我们将A的坐标直接代入畸变模型中,求…

Pytest教程__用例执行顺序(5)

在unittest中,测试用例的执行顺序与测试用例的名称有关,按照名称的ascii码排序的,并不是按照用例的编写顺序执行的。 pytest默认是按用例的编写顺序执行的 我们可以通过第三方包 pytest-ordering 来自定义我们用例的执行顺序。 方法是使用装…

14. 100ASK-V853-PRO开发板 ADB测试指南

100ASK-V853-PRO开发板 ADB测试指南 硬件要求: 100ASK-V853-PRO开发板 软件要求: 固件下载地址:链接:百度网盘 提取码:sp6a 固件位于资料光盘中的10_测试镜像/4.测试ADB/v853_linux_100ask_uart0.img 1.硬件连接 …

JMeter循环读取CSV文件实现接口批量测试

目录 前言: 1、添加线程组 2、添加HTTP信息头管理器 3、添加HTTP请求 4、添加察看结果树 5、添加循环控制器 6、在循环控制器下添加CSV配置文件 7、其他配置文件需要修改写入形式 8、执行CSV文件,查看结果 前言: JMeter可以通过CSV…

安装Canal

安装和配置Canal 安装和配置Canal1.开启MySQL主从1.1.开启binlog1.2.设置用户权限2.安装Canal2.1.创建网络2.3.安装Canal安装和配置Canal 下面我们就开启mysql的主从同步机制,让Canal来模拟salve 1.开启MySQL主从 Canal是基于MySQL的主从同步功能,因此必须先开启MySQL的主…

不同等级的高速PCB工程师,薪资差距有多大?

高速PCB设计在现代电子领域中扮演着很重要的角色,而高速PCB工程师的技能水平和经验对于项目的成功至关重要,下面本文将从地区分布、薪资水平、工作内容等多方面讨论对比不同等级的高速PCB工程师。 NO.1 初级高速PCB工程师 ①薪资水平 初级高速PCB工程师…

用代码实现一个简单计算器

作者主页:paper jie的博客_CSDN博客-C语言,算法详解领域博主 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《C语言》专栏,本专栏是针对于大学生,编程小白精心打造…

管理类联考——逻辑——知识篇——第四章 联言、选言(且、或)(5题,必考)

第四章 联言、选言(且、或)(5题,必考) 一、联言命题 联言命题是反映事物的若干种情况或者性质同时存在的复合命题 1.常见表达形式:A且B⟺即A又B⟺AB⟺虽然A但是B(语气强调B,逻辑是…

配置GitLab账号登录SonarQube

gitlab账号集成到sonarqube 创建个人访问令牌 确认之后可获得 来到sonarqube界面,创建gitlab配置 gitlab地址后面加上/api/v4 将访问令牌粘贴过来 保存即可 回到gitlab添加应用,名称随意最好有意义一眼知道是干嘛的 URI是sonarqube地址/oauth2/callback…

JavaSE进阶——网络编程

文章目录 前言一、网络编程二、通信1、两个重要的要素2、通信协议 三 、Socket四、基于TCP的网络编程1、单向通信1.1 服务端1.2 客户端 2、双向通信2.1 服务端2.2 客户端 3、传输对象3.1 服务端3.2 客户端 4、保持通信4.1 服务端4.2 客户端 五、基于UDP的网络编程1、单向通信1.…

软件开发流程管理中的6个重点

1、需求的确定 充分了解用户真实需求,与用户保持沟通交流;需求文档需详尽、准确,明确功能和客户期望;确保需求的合理性、完整性和可行性,并对需求进行优先级排序。 软件开发流程管理中的6个重点 2、设计原则 设计包括概…

【机器学习】一个简单的神经网络例子教你理解前向传播

在开始这个例子前,希望你已经了解了神经网络的相关内容,可以参见如下文章 https://blog.csdn.net/weixin_45434953/article/details/131048661 在计算机中,有一种很基础的运算称之为与运算,这是一个二元运算符, x 1 &…

web前端-TypeScript学习

web前端-TypeScript学习 TypeScript 介绍TypeScript 初体验安装编译TS的工具包编译并运行TS代码 TypeScript 常用类型类型注解常用基础类型原始类型数组类型类型别名函数类型对象类型接口元祖类型推论类型断言字面量类型枚举any类型typedof TypeScript 高级类型class类class的基…

6.Opencv-图像腐蚀、膨胀(开运算,闭运算)

1.图像腐蚀 这个操作会把前景物体的边界腐蚀掉。这是怎么做到的呢?卷积核沿着图像滑动,如果与卷积核对应的图像的所有像素值都是1,那么该区域的所有像素值就是1,否则为0。用于去除白噪声和断开两个连在一起的物体等。 语法&…

剑走偏锋,无头浏览器是什么神奇的家伙

大家好,我是风筝,公众号「古时的风筝」,专注于 Java技术 及周边生态。 我的个人网站:古时的风筝 浏览器是再熟悉不过的东西了,几乎每个人用过,比如 Chrome、FireFox、Safari,尤其是我们程序员&a…

ASEMI代理台湾光宝LTV-3120光耦合器中文资料

编辑-Z LTV-3120是一种高性能光耦,由于其可靠性、效率和多功能性,在各种应用中都很受欢迎。本文将全面了解LTV-3120其功能、应用以及它如何改进您的电子设计。 什么是光电耦合器? 光耦,也称为光隔离器,是一种利用光在…

时序数据库的流计算支持

一、时序数据及其特点 时序数据(Time Series Data)是基于相对稳定频率持续产生的一系列指标监测数据,比如一年内的道琼斯指数、一天内不同时间点的测量气温等。时序数据有以下几个特点: 历史数据的不变性数据的有效性数据的时效…

Linux:cp、mv、rm命令

1、cp命令:用于复制文件/文件夹,语法: cp [-r] 参数1 参数2 r参数可选,用于对文件夹进行复制,表示递归 参数1:Linux路径,表示被复制的文件或文件夹 参数2:Linux,表示要复…