23种设计模式之装饰者模式

深入理解装饰者模式

  • 一、装饰者模式简介
    • 1.1 定义
    • 1.2 模式类型
    • 1.3 主要作用
    • 1.4 优点
    • 1.5 缺点
  • 二、模式动机
  • 三、模式结构
  • 四、 装饰者模式的实现
    • 4.1 组件接口
    • 4.2 具体组件
    • 4.3 装饰者抽象类
    • 4.4 具体装饰者
    • 4.5 使用装饰者模式
    • 4.6 输出结果:
  • 五、 应用场景
    • 5.1 图形用户界面
    • 5.2 数据流处理
    • 5.3 日志功能
    • 5.4 监控和计数
  • 六、总结

在这里插入图片描述

一、装饰者模式简介

1.1 定义


  装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许在运行时动态地向对象添加新的功能,而不改变其结构和实现。装饰者模式通过组合来实现功能的扩展,它将功能划分成单一职责的类,并在需要时动态地组合这些功能实例化对象。

  根据《设计模式:可复用面向对象软件的基础》一书的定义,装饰者模式是:

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

1.2 模式类型


  结构型

1.3 主要作用


  1. 扩展功能:允许在运行时动态地给对象添加新的功能,而不需要修改对象的结构。这有助于遵循 OCP 原则。
  2. 灵活性和可重用性:装饰者模式通过创建装饰类来包裹原始对象,并在装饰类中添加功能,这样可以灵活组合不同的装饰器以达到不同的功能组合,同时原始类和装饰类都可以独立复用。
  3. 简化复杂度:对于有大量可选功能的对象,如果使用继承来实现每种可能的功能组合,会导致类的数量爆炸式增长。装饰者模式通过组合而非继承的方式来添加功能,大大减少了类的数量,简化了系统的复杂度。
  4. 保持接口一致性:装饰者模式保持了被装饰对象的接口一致,客户端代码可以透明地使用装饰后的对象,无需关心是否以及如何被装饰,这有利于代码的维护和扩展。
  5. 易于管理对象的责任:每个装饰者都负责单一职责,即添加特定的功能,这使得对象的责任更加清晰,便于管理和调试。

1.4 优点


  1. 灵活性高:可以在运行时任意组合装饰者,动态地扩展对象功能。
  2. 符合单一职责原则:每个装饰者类只负责增加一种功能,类的职责更加单一。
  3. 降低类复杂度:相比通过继承扩展功能,装饰者模式避免了大量的子类生成,从而减少类的复杂度。

1.5 缺点


  1. 对象数量增多:由于装饰者和被装饰者都是对象,这会增加系统中对象的数量,增加管理成本。
  2. 依赖过多:容易产生过多的小型对象,增加系统复杂性,理解和维护变得更加困难。

二、模式动机


装饰者模式的主要动机是应对以下几个问题:

  • 避免类爆炸:通过继承添加新功能会导致子类数量激增,维护起来十分困难。
  • 灵活组合功能:继承的组合方式是静态的,不够灵活。装饰者模式允许动态地组合功能。
  • 单一职责原则:通过将功能分解到不同的装饰类中,装饰者模式使每个类的职责更加单一,代码更易读易维护。

三、模式结构

在这里插入图片描述

装饰者模式通常涉及以下几个角色:

  • Component(抽象组件):定义一个对象接口,可以给这些对象动态地添加职责。
  • ConcreteComponent(具体组件):实现 Component 接口的具体对象,可以给这些对象添加一些职责。
  • Decorator(装饰者抽象类):继承 Component 接口,通常持有一个 Component 对象的引用,并定义一个与 Component 接口一致的接口。
  • ConcreteDecorator(具体装饰者):扩展 Decorator 类的具体装饰者,负责向组件添加新的职责。

四、 装饰者模式的实现


  我们将以一个具体的咖啡示例来介绍装饰者模式的实现。在这个例子中,我们有一个基本的咖啡对象,可以动态地添加不同的配料(如牛奶和糖)。

4.1 组件接口

// Java实现
public interface Coffee {double cost();String getDescription();
}

4.2 具体组件

public class SimpleCoffee implements Coffee {public double cost() {return 5.0;}public String getDescription() {return "Simple Coffee";}
}

4.3 装饰者抽象类

public abstract class CoffeeDecorator implements Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}public double cost() {return coffee.cost();}public String getDescription() {return coffee.getDescription();}
}

4.4 具体装饰者

public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}public double cost() {return super.cost() + 1.5;}public String getDescription() {return super.getDescription() + ", Milk";}
}public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}public double cost() {return super.cost() + 0.5;}public String getDescription() {return super.getDescription() + ", Sugar";}
}

4.5 使用装饰者模式

public class CoffeeShop {public static void main(String[] args) {Coffee coffee = new SimpleCoffee();System.out.println(coffee.getDescription() + " Cost: $" + coffee.cost());coffee = new MilkDecorator(coffee);System.out.println(coffee.getDescription() + " Cost: $" + coffee.cost());coffee = new SugarDecorator(coffee);System.out.println(coffee.getDescription() + " Cost: $" + coffee.cost());}
}

4.6 输出结果:

Simple Coffee Cost: $5.0
Simple Coffee, Milk Cost: $6.5
Simple Coffee, Milk, Sugar Cost: $7.0

五、 应用场景

在这里插入图片描述

5.1 图形用户界面


  在图形用户界面(GUI)框架中,装饰者模式广泛应用于实现各种控件的装饰功能。控件如按钮、文本框等可以用不同的装饰者类装饰来添加多种新功能,如滚动条、边框等。例如,Java Swing框架中的JComponent类就是使用类似装饰者模式的理念实现的。

5.2 数据流处理


  在数据流处理框架中,输入输出流是装饰者模式的另一个经典应用。JavaI/O流设计就是实现装饰者模式的一个优秀示例,如FileInputStreamBufferedInputStreamDataInputStream等通过装饰者模式组合,实现了灵活而强大的数据流操作功能。

5.3 日志功能


  日志记录功能的实现也是装饰者模式的理想应用场景。例如,传统的日志记录器Logger可以通过装饰者模式添加不同的日志处理和记录策略,如格式化日志、输出到文件、发送电子邮件等。

5.4 监控和计数


  在监控系统中,可以动态地为程序添加计数器、性能监控器等功能,以增强对系统运行状态的了解。

六、总结

  装饰者模式是一种强大的设计模式,它提供了一种灵活、可扩展的方式来动态地为对象添加新功能。通过这一模式,我们可以在不修改已有类代码的情况下,灵活地扩展系统功能,符合开闭原则单一职责原则。无论是在GUI编程中、日志功能增强,还是在数据流处理以及监控系统中,装饰者模式都能发挥重要作用。

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

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

相关文章

排序(堆排序、快速排序、归并排序)-->深度剖析(二)

前言 前面介绍了冒泡排序、选择排序、插入排序、希尔排序,作为排序中经常用到了算法,还有堆排序、快速排序、归并排序 堆排序(HeaSort) 堆排序的概念 堆排序是一种有效的排序算法,它利用了完全二叉树的特性。在C语言…

复分析——第9章——椭圆函数导论(E.M. Stein R. Shakarchi)

第 9 章 椭圆函数导论 (An Introduction to Elliptic Functions) The form that Jacobi had given to the theory of elliptic functions was far from perfection; its flaws are obvious. At the base we find three fundamental functions sn, cn and dn. These functio…

商汤上海AI实验室联合发布:自动驾驶全栈式高精度标定工具箱(含车、IMU、相机、激光雷达等的标定)

前言 在自动驾驶技术飞速发展的今天,传感器的精确标定对于确保系统性能至关重要。SensorsCalibration,一个专为自动驾驶车辆设计的标定工具箱,提供了一套全面的解决方案,用于校准包括IMU、激光雷达、摄像头和雷达在内的多种传感器…

基于Java平价平价汽车租赁系统设计和实现(源码+LW+部署讲解)

💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…

《RepViT Revisiting Mobile CNN From ViT Perspective》

期刊:CVPR 年份:2024 代码:http://https: //github.com/THU-MIG/RepViT 摘要 最近,与轻量级卷积神经网络(CNN)相比,轻量级视觉Transformer(ViTs)在资源受限的移动设备上表现出了更高的性能和更低的延迟。研究人员已…

无法访问指向的web服务器(或虚拟主机)的目录,请检查网络设置

微信公众平台,进行业务域名、JS接口安全域名、网页授权域名配置时,遇到的问题中有:无法访问指向的web服务器(或虚拟主机)的目录,请检查网络设置,这里简单记录一下处理过程。 关于这个问题首先保证下载…

【基于R语言群体遗传学】-1-哈代温伯格基因型比例

前言 群体遗传学是研究生物群体中基因的分布、基因频率和基因型频率的维持和变化的学科。它不仅探讨遗传病的发病频率和遗传方式,还研究基因频率和变化的规律,为预防、监测和治疗遗传病提供重要信息。R语言作为一种强大的统计分析工具,在群体…

mybatis实现多表查询

mybatis高级查询【掌握】 1、准备工作 【1】包结构 创建java项目,导入jar包和log4j日志配置文件以及连接数据库的配置文件; 【2】导入SQL脚本 运行资料中的sql脚本:mybatis.sql 【3】创建实体来包,导入资料中的pojo 【4】User…

TypeScript Project References npm 包构建小实践

npm 包输出 es/cjs 产物 在开发一个 npm 包时,通常需要同时输出 ES 模块和 CommonJS 模块的产物供不同的构建进行使用。在只使用tsc进行产物编译的情况下,我们通常可以通过配置两个独立的 tsconfig.json 配置文件,并在一个 npm script 中 执…

7.1作业

1.思维导图 2.在堆区申请两个长度为32的空间,实现两个字符串的比较【非库函数实现】 (1)定义函数,在对区申请空间 两个申请,主函数需要调用2次 (2)定义函数,实现字符串的输入 void input(char *p) (3)调用函数实现字符串比较…

BUT000增强字段BAPI结构激活出错(BUPA_CENTRAL_CI_CHANGE)

导语:BP主数据增强字段,需要使用BAPI:BUPA_CENTRAL_CI_CHANGE进行值写入,但是在SAP 2023以后的版本,激活会出错,原因是因为SAP的一个结构同时包含了BUS00_EEW以及BUS00_EEWX两个结构,导致结构字…

Spring Security 认证流程

Spring Scurity是spring生态下用于认证和授权的框架,具有高度的灵活性和可扩展行,本节主要对Spring Security的认证过程中进行概括性的介绍,主要介绍在该过程中,会涉及到哪些组件以及每个组件所承担的职责,希望大家可以…

电脑录音软件哪个好?7款录制音频工具大盘点,赶快学起来!(2024)

也许你渴望提取你最喜欢的节目的背景音乐,或者你希望录制自己的声音制作教程。如果是这样,你就需要一款优秀的电脑录音软件,来帮助你捕捉任何你想要的声音,而且不会损失音质。目前市场上存在着大量的录制音频工具,面对…

锁相环相位噪声仿真代码-汇总

24小时自动发货 所设计的压控振荡器输入电压为0.625V时,输出大致为500Mhz;输入电压为1.559时,输出电压大致为1Ghz 1.文件夹里面各个文件作用(包括参考书PLL PHASE NOISE ANALYSIS、lee的射频微电子、以及前人留下的matlab文件还有…

Ubuntu(通用)—网络加固—防DNS污染和ARP欺骗

1. 防DNS污染 DNS协议,把域名解析成ip地址,udp,这个过程会暴露访问的域名, 对这一传输过程加密(传输层用tcp)即为DoH(DNS over HTTPS)。 Browser(firefox)加固 由于Cloudflare、Quad8的DoH服务器不能用&…

Dns被莫名篡改的问题定位(笔记)

引言:最近发现用户的多台机器上出现了Dns被莫名修改的问题,从系统事件上看并未能正常确定到是那个具体软件所为,现在的需求就是确定和定位哪个软件具体所为。 解决思路: 首先到IPv4设置页面对Dns进行设置:通过ProcExp…

缺失d3dx9_43.dll是怎么回事?教你几种靠谱的解决方法

在日常生活和工作中,电脑已经成为我们不可或缺的工具。然而,在使用电脑的过程中,我们常常会遇到一些问题,其中之一就是软件运行时提示d3dx9_43.dll丢失。这个问题会导致软件游戏无法启动运行,但只要我们了解其原因和解…

LinkedHashMap、TreeMap

LinkedHashMap: 有序、不重复、无索引,底层是双链表 TreeMap:底层基于红黑树,可以对键进行排序 默认排序:integer和string都是从小到大排序 例题:

DP:子数组问题

文章目录 引言子数组问题介绍动态规划的基本概念具体问题的解决方法动态规划解法:关于子数组问题的几个题1.最大子数组和2.环形子数组的最大和3.乘积最大子数组4.乘积为正数的最长子数组长度5.等差数列划分 总结 引言 介绍动态规划(DP)在解决…