装饰器模式 详解 设计模式

news2024/11/16 6:31:38

装饰器模式

它允许你在不改变对象结构的情况下,动态地将新功能附加到对象上。

结构:

  • 抽象组件(Component):定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体组件类的父类或接口。
  • 具体组件(Concrete Component):是被装饰的原始对象,它定义了需要添加新功能的对象。
  • 抽象装饰器(Decorator):继承自抽象组件,它包含了一个抽象组件对象,并定义了与抽象组件相同的接口,同时可以通过组合方式持有其他装饰器对象。
  • 具体装饰器(Concrete Decorator):实现了抽象装饰器的接口,负责向抽象组件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。

图例:

平常假如要加一个配料,都需要修改餐品的源代码,但是随着配料的增多, 类会变得越来越庞大,等下类爆炸了。

public class Main {
    public static void main(String[] args) {
        FriedNoodles friedNoodles = new FriedNoodles();
        friedNoodles.addBacon();
        friedNoodles.addEgg();
        friedNoodles.addFish();

        System.out.println("Cost: $" + friedNoodles.getCost());
    }
}

案例:

假设有一个简单的咖啡店系统,其中有一个 Coffee 接口表示咖啡,它有一个方法 getCost() 来获取咖啡的价格。现在我们要给咖啡添加一些额外的配料,比如牛奶、摩卡和奶泡。

// 咖啡接口
interface Coffee {
    double getCost();
}

// 具体咖啡类
class SimpleCoffee implements Coffee {
    @Override
    public double getCost() {
        return 1.0;
    }
}

// 装饰者抽象类
abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }

    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

// 具体装饰者类
class Milk extends CoffeeDecorator {
    public Milk(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

class Mocha extends CoffeeDecorator {
    public Mocha(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 1.0;
    }
}

class Foam extends CoffeeDecorator {
    public Foam(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.3;
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        coffee = new Milk(coffee);
        coffee = new Mocha(coffee);
        coffee = new Foam(coffee);

        System.out.println("Cost: $" + coffee.getCost());
    }
}

通过组合不同的装饰者,可以在不改变原有咖啡对象的情况下,动态地添加额外的功能和费用。

使用场景:

  • 动态地给对象添加功能:当需要给对象动态地添加一些额外的功能,而且这些功能可以独立于该对象的创建。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)

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

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

相关文章

【c++】stack和queue模拟实现

> 作者简介:დ旧言~,目前大二,现在学习Java,c,c,Python等 > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:能手撕stack和queue模拟 > 毒鸡汤:…

Spring Cloud 构建面向企业的大型分布式微服务快速开发框架+技术栈介绍

分布式架构图 Cloud架构清单 Commonservice(通用服务) 1)清单列表 2)代码结构 Component(通用组件) 1)清单列表 2)代码结构 快速开发管理平台——云架构【系统管理平台】 一…

深度学习-回顾经典AlexNet网络:山高我为峰

深度学习-回顾经典AlexNet网络之山高我为峰 深度学习中,经典网络引领一波又一波的技术革命,从LetNet到当前最火的GPT所用的Transformer,它们把AI技术不断推向高潮。2012年AlexNet大放异彩,它把深度学习技术引领第一个高峰&#x…

MySQL:合并查询语句

1、查询表的数据 t_book表数据 SELECT * FROM db_book.t_book; t_booktype表数据 SELECT * FROM db_book.t_booktype; 提醒: 下面的查询操作的数据来自上图查询表的数据 2. 使用 UNION 查询结果合并,会去掉重复的数据 使用UNION关键字是,数…

linux_day04

大纲:命令,vim,gcc,编译工具,生成代码,调试,库makefile,系统编程 文件系统:文件属性,文件内容,万物皆文件(不在内存中的是文件&#…

新书速览|Python数据科学应用从入门到精通

系统教授数据科学与Python实战,涵盖线性回归、逻辑回归、决策树、随机森林、神经网 本书内容 随着数据存储、数据处理等大数据技术的快速发展,数据科学在各行各业得到广泛的应用。数据清洗、特征工程、数据可视化、数据挖掘与建模等已成为高校师生和职场…

Python学习 问题汇总(None)

None的总结 在Python中,对于一些变量往往需要赋初始值,为了防止初始值与正常值混淆,通常采用置0或置空操作,置0比较简单,置空则是赋NoneNone是一个空值,可以赋给任意类型的变量,起到占位的作用…

【Godot4自学手册】第十七节主人公的攻击和敌人的受伤

本节主要学习主人公是如何向敌人发起进攻的,敌人是如何受伤的,受伤时候动画显示,击退效果等。其原理和上一节内容相同,不过有许多细节需要关注和完善。 一、修改Bug 在本节学习之前,我将要对上一节的代码进行完善&am…

基础小白快速入门Python------>模块的作用和意义

模块, 这个词听起来是如此的高大威猛,以至于萌新小白见了瑟瑟发抖,本草履虫见了都直摇头,好像听上去很难的样子,但是但是,年轻人,请听本少年细细讲述,他只是看起来很难,实…

MySql安全加固:可信IP地址访问控制 设置密码复杂度

MySql安全加固:可信IP地址访问控制 & 设置密码复杂度 1.1 可信IP地址访问控制1.2 设置密码复杂度 💖The Begin💖点点关注,收藏不迷路💖 1.1 可信IP地址访问控制 当您在创建用户时使用’%作为主机部分,…

【爬虫逆向实战 逆向滑块 Python+Node】今天逆向的网站有点嘿嘿,还是仅供学习,别瞎搞

逆向日期:2024.03.01 使用工具:Node.js、Python 加密方法:AES标准算法 文章全程已做去敏处理!!! 【需要做的可联系我】 AES解密处理(直接解密即可)(crypto-js.js 标准算…

大模型生成,Open API调用

大模型是怎么生成结果的 通俗原理 其实,它只是根据上文,猜下一个词(的概率)…… OpenAI 的接口名就叫【completion】,也证明了其只会【生成】的本质。 下面用程序演示【生成下一个字】。你可以自己修改 prompt 试试…

Appium移动端自动化测试-(Java)

目录 环境搭建ADB调试工具adb构成adb工作原理adb常用命令电脑连接多个设备跟模拟器使用adb包名与界面名的概念如何获取包名和界面名文件传输获取app启动时间获取手机日志其他命令 Appium全自动化测试框架(python)冲错了序言 环境搭建Appium客户端安装App…

IDEA切换 Springboot初始化 URL

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 往期热门专栏回顾 专栏…

【矩阵】【方向】【素数】3044 出现频率最高的素数

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 素数 矩阵 方向 LeetCode 3044 出现频率最高的素数 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格,你可以按以下方式生成数字: 最多有 8 条路径可以选择:东&am…

C语言基础(三)——函数

六、函数 6.1 函数的声明与定义—嵌套调用 6.1.1 函数的声明与定义 函数间的调用关系是,由主函数调用其他函数,其他函数也可以互相调用,同一个函数可以背一个或多个函数调用任意次。 下例中有两个c文件, func.c是子函数printstar和print_me…

光伏气象站的组成

TH-FGF9光伏气象站主要由以下几个部分组成: 光伏组件:光伏组件是光伏气象站的核心部分,其主要功能是将太阳能转化为电能,为气象站的各项设备提供电源。光伏组件通常由多个光伏电池板组成,能够有效地吸收并利用太阳能。…

C++:String类的使用

创作不易,感谢三连!! 在C语言中,我们想要存储字符串的话必须要用字符数组 char str[]"hello world"这其实是将在常量区的常量字符串拷贝到数组中,我们会在数组的结尾多开一个空间存储\0,这样我…

pyuic生成py文件到指定文件夹

pyuic生成py文件到指定文件夹 关于如何在pycharm配置外部工具的方法这里不做赘述,本文主要说明,如何利用pyuic将ui文件生成到指定的项目目录中。 前提条件:已配置的pyuic工具可以正常使用生成文件到目录中。 一、打开外部工具配置页面 打开…

吸猫毛空气净化器哪个好?推荐除猫毛好的宠物空气净化器品牌

如今,越来越多的家庭选择养宠物!虽然家里变得更加温馨,但养宠可能会带来异味和空气中的毛发增多可能会引发健康问题,这也是一个大问题。 但我不想家里到处都是异味,尤其是便便的味道,所以很需要一款能够处…