装饰者模式:打破继承限制,实现灵活的功能扩展

news/2024/2/29 16:52:40/文章来源:https://blog.csdn.net/Mrxiao_bo/article/details/135647029

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

装饰者模式:打破继承限制,实现灵活的功能扩展

    • 前言
    • 装饰者模式简介
    • 装饰者模式的工作原理
    • 实际应用
    • java代码实现
    • 结语

前言

在软件开发中,我们经常面临着需求的变化和新功能的添加。但是,传统的继承方式往往使代码变得复杂且难以维护。在本文中,我们将介绍一种强大的设计模式 - 装饰者模式,它可以让你轻松实现功能扩展,同时保持代码的简洁性。让我们一起探索这个设计模式的神奇之处。

装饰者模式简介

装饰者模式是一种结构型设计模式,它允许你动态地为对象添加额外的行为或功能,而不需要修改其原始类的代码。这种模式是基于组合的思想,它允许你创建一系列装饰类,这些装饰类包装了一个具体的组件对象,以扩展或修改其功能。

基本概念和用途:
装饰者模式的基本概念包括以下几个要点:

  1. 组件(Component):这是一个接口或抽象类,定义了要被装饰的对象的基本行为。
  2. 具体组件(Concrete Component):这是实现了组件接口的具体类,是被装饰的原始对象。
  3. 装饰者(Decorator):这是一个抽象类,也实现了组件接口,但通常不包含完整的功能,而是用来包装具体组件对象。
  4. 具体装饰者(Concrete Decorator):这是实现了装饰者抽象类的具体类,它扩展或修改了组件的功能,并通过组合关系持有一个具体组件对象。

优势与应用场景:
装饰者模式的优势包括:

  1. 开放封闭原则:它允许你在不修改原始类代码的情况下扩展对象的功能,符合开放封闭原则,使代码更容易维护和扩展。

  2. 单一职责原则:每个具体装饰者都只关注特定的功能扩展,不会导致类的臃肿。

  3. 灵活性:你可以根据需要组合多个装饰者,以创建各种不同的对象组合,满足不同的需求。

应用场景包括:

  1. 动态添加功能:当需要动态地为对象添加功能而不影响其原始类时,装饰者模式非常有用,例如,在图形编辑器中添加边框、滚动条等功能。

  2. 避免子类爆炸:当存在大量子类时,使用装饰者模式可以避免创建大量的子类,而是通过组合不同的装饰者来实现功能扩展。

  3. 扩展外部库:当无法修改外部库或类的代码时,可以使用装饰者模式来扩展其功能,而不需要继承或修改原始类。

总之,装饰者模式是一种非常有用的设计模式,可以帮助你在不破坏原有代码结构的情况下为对象添加新的功能或修改现有功能。在软件开发中,特别是在需要灵活扩展和定制对象行为的情况下,装饰者模式是一个有力的工具。

装饰者模式的工作原理

装饰过程的工作流程如下:

  1. 创建一个具体组件对象,它实现了组件接口,并提供了基本的功能。
  2. 创建具体装饰者对象,它也实现了组件接口,并通过构造函数或其他方式持有具体组件对象。
  3. 可选地,创建更多的具体装饰者对象,它们可以按照一定的顺序包装具体组件或其他装饰者。
  4. 当需要使用对象时,客户端可以使用装饰者链的最外层装饰者对象来操作对象。每个装饰者对象可以添加额外的功能,然后将操作传递给下一个装饰者或具体组件。

动态添加功能的关键在于,你可以在运行时按需创建并组合不同的装饰者,从而实现对象的多层功能扩展,而不需要修改原始组件的代码。这使得你可以灵活地定制对象的行为,而且可以随时添加或移除装饰者,以满足不同的需求。这种灵活性是装饰者模式的核心特点。

实际应用

装饰者模式在实际项目中有许多应用场景,下面我将展示一个示例案例以及如何通过装饰者模式实现功能的灵活扩展。

示例案例 - 咖啡店订单系统

假设你正在开发一个咖啡店订单系统,你有一个基本的咖啡类(Concrete Component)表示普通的咖啡,这个咖啡有基本的价格和描述。然后,你想让顾客能够在点咖啡时选择不同的配料(装饰者),如牛奶、糖和巧克力,以扩展咖啡的功能。

  1. 组件接口(Coffee):这个接口定义了咖啡的基本行为,包括获取价格和描述。

  2. 具体组件(SimpleCoffee):这是基本的咖啡类,实现了组件接口,提供了咖啡的基本价格和描述。

  3. 装饰者(CoffeeDecorator):这是一个抽象类或接口,也实现了组件接口,用来包装具体组件对象。

  4. 具体装饰者(MilkDecorator、SugarDecorator、ChocolateDecorator 等):这些是具体装饰者类,它们扩展了咖啡的功能,比如牛奶装饰者可以在基本咖啡上添加牛奶,并调整价格和描述。

通过这个示例案例,你可以看到装饰者模式的实际应用:

  • 当顾客点一杯咖啡时,你可以创建一个具体组件对象,如 SimpleCoffee。
  • 然后,你可以根据顾客的选择,逐步用具体装饰者对象包装这个咖啡,例如,先加入牛奶装饰者,再加入糖装饰者。
  • 最后,你可以通过最外层的装饰者对象来获取咖啡的价格和描述,它会依次调用各个装饰者的方法,从而获得最终的结果。

这个示例展示了如何通过装饰者模式实现功能的灵活扩展。你可以根据需要组合不同的装饰者,以创建各种不同口味和价格的咖啡,而不需要修改咖啡的基本类或代码。这种模式使得系统具有高度的可扩展性,能够应对不断变化的需求,同时保持代码的清晰和可维护性。

java代码实现

当使用Java实现装饰者模式时,你可以按照以下步骤创建示例案例中的咖啡店订单系统。首先,我们定义组件接口 Coffee,具体组件 SimpleCoffee,以及装饰者抽象类 CoffeeDecorator

// 定义组件接口
interface Coffee {double getCost();String getDescription();
}// 具体组件
class SimpleCoffee implements Coffee {@Overridepublic double getCost() {return 5.0; // 基础咖啡价格}@Overridepublic String getDescription() {return "Simple Coffee";}
}// 装饰者抽象类
abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic double getCost() {return decoratedCoffee.getCost();}@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}
}

接下来,我们创建具体的装饰者类,例如牛奶装饰者 MilkDecorator 和巧克力装饰者 ChocolateDecorator

// 具体装饰者 - 牛奶装饰者
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return super.getCost() + 2.0; // 牛奶价格}@Overridepublic String getDescription() {return super.getDescription() + ", Milk";}
}// 具体装饰者 - 巧克力装饰者
class ChocolateDecorator extends CoffeeDecorator {public ChocolateDecorator(Coffee coffee) {super(coffee);}@Overridepublic double getCost() {return super.getCost() + 3.0; // 巧克力价格}@Overridepublic String getDescription() {return super.getDescription() + ", Chocolate";}
}

现在,你可以在客户端代码中创建不同口味的咖啡并添加装饰者,示例代码如下:

public class CoffeeShop {public static void main(String[] args) {// 创建基础咖啡Coffee coffee = new SimpleCoffee();System.out.println("Cost: $" + coffee.getCost()); // 输出基础咖啡价格System.out.println("Description: " + coffee.getDescription()); // 输出基础咖啡描述// 添加牛奶装饰Coffee milkCoffee = new MilkDecorator(coffee);System.out.println("Cost: $" + milkCoffee.getCost()); // 输出加牛奶的价格System.out.println("Description: " + milkCoffee.getDescription()); // 输出加牛奶的描述// 添加巧克力装饰Coffee chocolateMilkCoffee = new ChocolateDecorator(milkCoffee);System.out.println("Cost: $" + chocolateMilkCoffee.getCost()); // 输出加巧克力的价格System.out.println("Description: " + chocolateMilkCoffee.getDescription()); // 输出加巧克力的描述}
}

这段代码演示了如何使用装饰者模式创建不同口味的咖啡,并通过添加装饰者来扩展咖啡的功能。运行此代码将输出咖啡的价格和描述,显示了装饰者模式的动态功能扩展特性。

结语

装饰者模式是设计模式中的一颗明珠,它让你可以轻松实现功能扩展,同时保持代码的简洁性。通过本文的学习和实践,你将能够更好地理解装饰者模式的原理和应用,为你的软件开发提供更多的选择。让我们一同探索设计模式的奇妙世界,掌握装饰者模式的神奇魔法。

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

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

相关文章

rsync全面讲解

rsync 是一个常用的 Linux 应用程序,用于文件同步。 它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cp和mv命令。 它名称里面…

基础面试题整理4

1.mybatis的#{}和${}区别 #{}是预编译处理,${}是字符串替换#{}可以防止SQL注入,提高安全性 2.mybatis隔离级别 读未提交 READ UNCOMMITED:读到了其他事务中未提交的数据,造成"脏读","不可重复读","幻读&…

Python进程池multiprocessing.Pool

环境: 鲲鹏920:192核心 内存:756G python:3.9 python单进程的耗时 在做单纯的cpu计算的场景,使用单进程核多进程的耗时做如下测试: 单进程情况下cpu的占用了如下,占用一半的核心数: 每一步…

git 提炼笔记

1、设置用户名和邮箱(邮箱可以不是真的) git config --global user.name test101 // 设置用户名为 test101git config --global user.email test101test101.cn // 设置邮箱为test101test101.cn2、查看用户名和邮箱 git config --global user.name git…

【SpringBoot框架篇】35.kafka环境搭建和收发消息

kafka环境搭建 kafka依赖java环境,如果没有则需要安装jdk yum install java-1.8.0-openjdk* -y1.下载安装kafka kafka3.0版本后默认自带了zookeeper,3.0之前的版本需要单独再安装zookeeper,我使用的最新的3.6.1版本。 cd /usr/local wget https://dlcdn.apache.…

Redis主从架构、哨兵集群原理实战

1.主从架构简介 背景 单机部署简单,但是可靠性低,且不能很好利用CPU多核处理能力生产环境必须要保证高可用,一般不可能单机部署读写分离是可用性要求不高、性能要求较高、数据规模小的情况 目标 读写分离,扩展主节点的读能力&…

canvas绘制美队盾牌

查看专栏目录 canvas示例教程100专栏,提供canvas的基础知识,高级动画,相关应用扩展等信息。canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重…

STC8H8K蓝牙智能巡线小车——1. 环境搭建(基于RTX51操作系统)

1. 基本介绍 开发环境准备:Keil uVision5 烧录软件:STC-ISP(V6.92A) 芯片: STC8H8K64U-45I-LQFP64 芯片引脚: 2.创建项目 打开Keil,点击【Project】,选择【new uVersion proje…

快乐学Python,如何使用爬虫从网页中提取感兴趣的内容?

前面的内容,我们了解了使用urllib3和selenium来下载网页,但下载下来的是整个网页的内容,那我们又怎么从下载下来的网页中提取我们自己感兴趣的内容呢?这里就需要Python的另一个库来实现-BeautifulSoup。 BeautifulSoup 是一个 Py…

数据仓库(2)-认识数仓

1、数据仓库是什么 数据仓库 ,由数据仓库之父比尔恩门(Bill Inmon)于1990年提出,主要功能仍是将组织透过资讯系统之联机事务处理(OLTP)经年累月所累积的大量资料,透过数据仓库理论所特有的资料储存架构,做…

可以在微信群里使用midjourney,gpt4,gemini,文心一言4.0,且免费

免费使用gpt4和midjourney 免费使用 参考链接: https://chat.xutongbao.top/

【银行测试】银行项目,信用卡业务测试+常问面试(三)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 银行测试-信用卡业…

轻松识别Midjourney等AI生成图片,开源GenImage

AIGC时代,人人都可以使用Midjourney、Stable Diffusion等AI产品生成高质量图片,其逼真程度肉眼难以区分真假。这种虚假照片有时会对社会产生不良影响,例如,生成公众人物不雅图片用于散播谣言;合成虚假图片用于金融欺诈…

Angular系列教程之DOM操作

文章目录 引言1. ElementRef2. Renderer23. ViewChild结论 引言 在Angular中,DOM操作是开发Web应用程序的一个重要方面。通过对DOM进行操作,我们可以动态地修改页面内容、样式和元素行为。本文将详细介绍如何在Angular中进行DOM操作,并提供相…

从数据可视化到场景渲染:山海鲸的创新与实践

作为山海鲸的开发者,我们深知可视化模型场景渲染在数据分析和决策支持中的重要作用。因此在保证山海鲸可视化软件免费编辑、分享、部署的同时也在场景渲染方面不断优化,本文将介绍山海鲸在可视化模型场景渲染方面的技术革新与实践探索。 首先&#xff0…

【STM32】STM32学习笔记-USART串口数据包(28)

00. 目录 文章目录 00. 目录01. 串口简介02. HEX数据包03. 文本数据包04. HEX数据包接收05. 文本数据包接收06. 预留07. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持…

Go并发快速入门:Goroutine

Go并发:Goroutine 1.并发基础概念:进程、线程、协程 (1) 进程 可以比作食材加工的一系列动作 进程就是程序在操作系统中的一次执行过程,是由系统进行资源分配和调度的基本单位,进程是一个动态概念,是程序在执行过程…

unity面试题

一:什么是协同程序? 在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程很像多线程,但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足。 二:Unity3d中的碰…

汽车线束的汽配企业MES管理系统解决方案

随着科技的飞速发展和环保需求的日益提升,新能源汽车在全球范围内崭露头角,成为未来出行的主导力量。在这股浪潮中,中国凭借其强大的研发实力和市场敏锐度,迅速崛起为新能源汽车领域的佼佼者。而作为汽车数字化控制与智能化应用的…

Excel地址

解题思路: 根据题中歪歪和笨笨的话可以有两种解法。 1.输入的数为多大,则循环1多少次,当值为27时就要进行进位操作。这时要分情况讨论。 当集合中元素为一个时,如26,则需要变为1 1,集合元素个数加一。 当…