设计模式之 装饰者模式

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许通过动态地给对象添加额外的功能,而不需要修改对象的结构。装饰者模式通过创建一个装饰类来封装原始对象,并为原始对象提供附加的功能。这种模式使得我们能够在运行时扩展对象的功能,避免了继承的局限性。

装饰者模式的核心思想是在不改变对象自身的情况下,给对象添加额外的职责。通过使用装饰者,可以使得对象的功能变得更加灵活,可以根据需要动态地添加功能。

一、装饰者模式的结构

装饰者模式的结构通常包括以下几个角色:

  1. 组件接口(Component)

    这是一个抽象的接口或类,它定义了被装饰的对象的基本功能。所有的具体组件(ConcreteComponent)和装饰者(Decorator)都需要实现或继承该接口。
  2. 具体组件(ConcreteComponent)

    具体组件是装饰者模式中的核心类,它实现了组件接口,并定义了具体的功能。它是被装饰的对象。
  3. 装饰者(Decorator)

    装饰者类是一个抽象类,它也实现了组件接口,并持有一个组件对象的引用。它的主要作用是通过在方法中调用组件对象的方法,然后再为其添加新的功能。
  4. 具体装饰者(ConcreteDecorator)

    具体装饰者是装饰者的子类,它在装饰者类的基础上,提供附加功能的实现。通过具体装饰者,可以实现不同的装饰功能。

二、装饰者模式的工作原理

装饰者模式的基本工作原理是:通过将一个组件(具体对象)传递给装饰者类,并通过装饰者来扩展其功能。装饰者类通常会持有一个指向组件接口的引用,这样就可以在不改变原有类的情况下,通过装饰者对象动态添加额外的功能。

装饰者模式可以理解为“在现有对象的外层包裹一个新的类”,通过组合的方式,而不是继承的方式,来扩展对象的功能。

三、装饰者模式的示例

示例:咖啡店

在咖啡店的业务中,我们可能需要为每一杯咖啡添加不同的配料(如牛奶、糖等)。我们可以使用装饰者模式来实现这个需求。

  • 抽象咖啡(组件接口)
    public class Coffee {
    
        private double price;
        private String desc;//描述
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        public Coffee() {
    
        }
    
        public Coffee(double price, String desc) {
            this.price = price;
            this.desc = desc;
        }
    }
  • 具体咖啡(具体组件)
    public class Americano extends Coffee{
        public Americano() {
            super(10,"美式咖啡");
        }
    }
    public class Latte extends Coffee{
        public Latte() {
            super(8, "拿铁咖啡");
        }
    }
  •  装饰者类
    public class Decorator extends Coffee{
        private Coffee coffee;
    
        public Coffee getCoffee() {
            return coffee;
        }
    
        public void setCoffee(Coffee coffee) {
            this.coffee = coffee;
        }
    
        public Decorator(double price, String desc, Coffee coffee) {
            super(price, desc);
            this.coffee = coffee;
        }
    }
    
  •  具体装饰者(加糖,加奶)
    public class Sugar extends Decorator {
        public Sugar(Coffee coffee){
            super(1,"加糖",coffee);
        }
    
        @Override
        public double getPrice() {
            return getCoffee().getPrice() + super.getPrice();
        }
    
        @Override
        public String getDesc() {
            return getCoffee().getDesc() + super.getDesc();
        }
    }
    
    public class Milk extends Decorator{
        public Milk(Coffee coffee) {
            super(2, "加奶", coffee);
        }
        @Override
        public double getPrice() {
            return getCoffee().getPrice() + super.getPrice();
        }
    
        @Override
        public String getDesc() {
            return getCoffee().getDesc() + super.getDesc();
        }
    }
  •  测试类
    public class Client {
        public static void main(String[] args) {
            Coffee coffee = new Americano();
            System.out.println(coffee.getDesc() + ": " + coffee.getPrice());
    
            coffee = new Sugar(coffee);
            System.out.println(coffee.getDesc() + ": " + coffee.getPrice());
    
            coffee = new Milk(coffee);
            System.out.println(coffee.getDesc() + ": " + coffee.getPrice());
        }
    }
  •  运行结果
 
解释
  • Coffee是一个基础的咖啡类,定义了咖啡的基础属性
  • Decorator是装饰者类,它包装了一个Coffee对象
  • MilkSugar是具体装饰者类,它们分别为咖啡添加了牛奶和糖的费用。
  • 客户端可以选择性地给咖啡添加不同的装饰(例如,先加牛奶,再加糖),而且这些装饰类可以按需组合。

四、装饰者模式的优缺点

优点:
  1. 更灵活的扩展功能:

    • 装饰者模式可以在不修改原始类的情况下,动态地给对象添加新功能,从而增加了系统的灵活性。
  2. 避免了类的爆炸性增长:

    • 使用装饰者模式可以避免过多的继承层次结构,如果使用继承的话,会导致类的数量急剧增加。而通过装饰者,可以根据需要动态添加功能,保持系统结构的简洁性。
  3. 支持对象的职责分离:

    • 每个装饰者负责提供一个具体的功能,可以使得不同的功能职责分离,避免单一类承担过多的责任。
  4. 符合开闭原则:

    • 装饰者模式遵循了开闭原则,即对扩展开放,对修改封闭。通过装饰器,我们可以在不修改原始代码的情况下为对象添加新功能。
缺点:
  1. 增加了系统复杂度:

    • 由于使用了多个装饰类,可能会导致系统中装饰类的数量过多,增加了管理和理解的难度。
  2. 可能会使得代码变得难以追踪:

    • 因为装饰者会包裹原始对象并改变其行为,过多的装饰者链可能使得程序的行为变得难以理解和调试。
  3. 性能开销:

    • 每增加一个装饰者,都会增加一次方法调用的开销。如果装饰链很长,可能会影响性能。

五、装饰者模式的应用场景

装饰者模式适用于以下几种场景:

  1. 需要动态地为对象添加功能时:

    • 如果一个类需要动态地增加一些附加功能,而不是通过继承来实现,装饰者模式是一个很好的选择。
  2. 避免类的爆炸性增长:

    • 如果通过继承的方式去增加功能,会导致类的数量激增。使用装饰者模式,可以避免这种问题,并保持代码的简洁性。
  3. 功能可以独立扩展:

    • 如果对象的功能是可以独立扩展的,可以使用装饰者模式。在每个装饰类中,只负责某个特定功能的增强。
  4. 允许客户端按需增加功能:

    • 如果希望用户可以选择性地为对象增加某些功能,可以使用装饰者模式。每个装饰者都可以单独工作,也可以组合使用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【架构】主流企业架构Zachman、ToGAF、FEA、DoDAF介绍

文章目录 前言一、Zachman架构二、ToGAF架构三、FEA架构四、DoDAF 前言 企业架构(Enterprise Architecture,EA)是指企业在信息技术和业务流程方面的整体设计和规划。 最近接触到“企业架构”这个概念,转念一想必定和我们软件架构…

vue3:使用插件递归组件

vue3:使用插件递归组件 首先安装插件 npm i unplugin-vue-define-optionsvite.config.ts 配置插件 // vite.config.ts// 引入 unplugin-vue-define-options import DefineOptions from "unplugin-vue-define-options"; export default defineConfig({// 注册插件 De…

开源远程桌面工具:RustDesk

在远程办公和远程学习日益普及的今天,我们经常需要远程访问办公电脑或帮助他人解决电脑问题。 市面上的远程控制软件要么收费昂贵,要么需要复杂的配置,更让人担心的是数据安全问题。 最近我发现了一款名为 RustDesk 的开源远程桌面工具&…

springboot整合hive

springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

ChatGPT 与其他 AI 技术在短视频营销中的技术应用与协同策略

摘要&#xff1a; 本文深入探讨了 ChatGPT 及其他 AI 技术在短视频营销中的应用。从技术层面剖析了这些技术如何助力短视频内容创作、个性化推荐、用户互动以及营销效果评估等多方面&#xff0c;通过具体方法分析、数据引用与大模型工具介绍&#xff0c;旨在为短视频营销领域提…

国土安全部发布关键基础设施安全人工智能框架

美国国土安全部 (DHS) 发布建议&#xff0c;概述如何在关键基础设施中安全开发和部署人工智能 (AI)。 https://www.dhs.gov/news/2024/11/14/groundbreaking-framework-safe-and-secure-deployment-ai-critical-infrastructure 关键基础设施中人工智能的角色和职责框架 https:/…

xtu oj 前缀和

样例输入 3 3 2 1 2 3 1 2 3 2 1 2 3 -1 -2 3 3 -4 3 1 4 2 1 样例输出 0 3 3 解题思路&#xff1a;排序前缀和二分查找 因为数组b是可以插入到数组a任意位置&#xff0c;要想k最大&#xff0c;就要尽可能把b的小数插到a数组的前面。所以&#xff0c;用qsort方法对数组b进…

Nexus搭建go私有仓库,加速下载go依赖包

一、搭建go私库 本文我们梳理一下go依赖包的私库搭建以及使用。 它只分为proxy和group两种仓库&#xff0c;这一点和maven仓库有所不同。 1、创建Blob Stores 为了区分不同的私库依赖包&#xff0c;存储的位置分隔开。 2、新建go proxy官网 Remote storage&#xff1a;htt…

CPU算法分析LiteAIServer摄像机实时接入分析平台固废检测算法助力环保

随着城市化进程的加速和工业化发展的不断深入&#xff0c;固体废弃物的处理问题逐渐成为了一个全球性的挑战。传统的固废检测方法主要依赖于人工巡查和抽样检测&#xff0c;这种方式不仅效率低下&#xff0c;而且难以实现对固体废弃物的全面覆盖和实时监测。为了解决这一问题&a…

国内镜像android studio

Android SDK在线更新镜像服务器 1.中国科学院协会镜像站: 部分地区无法使用 ◦IPV4/IPV6: mirrors.opencas.cn 端口&#xff1a;80 ◦IPV4/IPV6: mirrors.opencas.org 端口&#xff1a;80 ◦IPV4/IPV6: mirrors.opencas.ac.cn 端口&#xff1a;80 2.上海GDG镜像服务器地址…

Ubuntu上安装MySQL并且实现远程登录

目录 下载网络工具 查看网络连接 更新系统软件包&#xff1b; 安装mysql数据库 查看mysql数据库状态 以数字ip形式显示mysql的监听状态。&#xff08;默认监听端口是3306&#xff09; 查看安装mysql数据库时系统创建的目录信息。 根据查询到的系统用户名以及随机密码&a…

从零开始认识显卡

显卡&#xff08;GPU&#xff0c;全称为Graphics Processing Unit&#xff09;&#xff0c;是电脑中专门负责图形处理的硬件组件。以下是从零开始认识显卡的简单介绍&#xff1a; 1. 显卡的基本组成 显卡通常由以下几个主要部分组成&#xff1a; GPU核心&#xff1a;显卡的“…

mac安装Pytest、Allure、brew

安装环境 安装pytest 命令 pip3 install pytest 安装allure 命令&#xff1a;brew install allure 好吧 那我们在安装allure之前 我们先安装brew 安装brew 去了官网复制了命令 还是无法下载 如果你们也和我一样可以用这个方法哦 使用国内的代码仓库来执行brew的安装脚本…

【Vue】 npm install amap-js-api-loader指南

前言 项目中的地图模块突然打不开了 正文 版本太低了&#xff0c;而且Vue项目就应该正经走项目流程啊喂&#xff01; npm i amap/amap-jsapi-loader --save 官方说这样执行完&#xff0c;就这结束啦&#xff01;它结束了&#xff0c;我还没有&#xff0c;不然不可能记录这篇文…

三极管工作原理,以及小电流,如何驱动大电流

因为研究【自动下载电路实现】&#xff0c;涉及到三极管内容&#xff0c;之前看过&#xff0c;现在回看之前的笔记&#xff0c;一点印象都没了&#xff0c;于是&#xff0c;想了个办法&#xff0c;记住它 个人联想&#xff0c;不喜绕道&#xff0c;只是帮助个人记忆的 标题也是…

一文了解倾斜摄影

倾斜摄影是通过从一个垂直、四个倾斜、五个不同的视角同步采集影像&#xff0c;获取到丰富的建筑物顶面及侧视的高分辨率纹理。它不仅能够真实地反映地物情况&#xff0c;高精度地获取物方纹理信息&#xff0c;还可通过先进的定位、融合、建模等技术&#xff0c;生成真实的三维…

浅谈,华为切入具身智能赛道

近期&#xff0c;全球具身智能大模型&#xff08;机器人“通用大脑”&#xff09;赛道热闹非凡&#xff0c;科技大厂、初创公司接连发布重磅消息。 国外&#xff1a; 10月底&#xff0c;美国科技巨头【Meta】旗下基础人工智能研究 &#xff08;FAIR&#xff09;公布公司触摸感…

Spring |(二)IOC相关内容 | bean

文章目录 &#x1f4da;bean基础配置&#x1f407;bean的id和class&#x1f407;bean的name属性&#x1f407;bean作用范围scope配置&#x1f407;bean基础配置小结 &#x1f4da;bean实例化&#x1f407;构造方法实例化&#xff08;常用&#xff09;&#x1f407;静态工厂实例…

网络安全-企业环境渗透2-wordpress任意文件读FFmpeg任意文件读

一、 实验名称 企业环境渗透2 二、 实验目的 【实验描述】 操作机的操作系统是kali 进入系统后默认是命令行界面 输入startx命令即可打开图形界面。 所有需要用到的信息和工具都放在了/home/Hack 目录下。 本实验的任务是通过外网的两个主机通过代理渗透到内网的两个主机。…

Java 对象头、Mark Word、monitor与synchronized关联关系以及synchronized锁优化

1. 对象在内存中的布局分为三块区域&#xff1a; &#xff08;1&#xff09;对象头&#xff08;Mark Word、元数据指针和数组长度&#xff09; 对象头&#xff1a;在32位虚拟机中&#xff0c;1个机器码等于4字节&#xff0c;也就是32bit&#xff0c;在64位虚拟机中&#xff0…