装饰器模式、代理模式、适配器模式对比

news2024/11/26 23:38:47

装饰器模式、代理模式和适配器模式都是结构型设计模式,它们的主要目标都是将将类或对象按某种布局组成更大的结构,使得程序结构更加清晰。这里将装饰器模式、代理模式和适配器模式进行比较,主要是因为三个设计模式的类图结构相似度较高、且功能上存在一定的相似度。接下来将一步步说明。

装饰器模式

装饰器模式是一种结构型设计模式,用来动态地给一个对象增加一些额外的职责,即增加该对象额外的功能,其别名为包装器(Wrapper)。在装饰器模式中,会定义一个装饰器类,声明了一个指向被封装对象的引用成员变量,并定义了可动态添加到被封装对象的具体行为。其类图表示如下:

请添加图片描述

从类图结构上来说,装饰器模式并没有直接修改对象,而是在不影响对象的情况下,以动态、透明的方式给单个对象添加职责。就增加对象功能来说,装饰器模式比生成子类实现更为灵活。
装饰器模式主要适用于需要给对象动态地增加一些额外职责的场景。装饰器能将业务逻辑组织为层次结构,开发者可为各层创建一个装饰器,在运行时将各种不同逻辑组合成对象。特别是当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时,可以考虑使用装饰器模式。不能采用继承的情况主要有三类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类);第三类是需要扩展的类来源于三方件,对于三方件的代码,如无特殊说明,是不建议使用继承来扩展功能的。
由于被装饰对象和装饰对象可以独立变化,用户可以根据需要增加新的被装饰类和装饰类,原有代码无须改变,这符合"开闭原则"。相比通过继承关系扩展对象的功能,装饰器模式可以提供比继承更多的灵活性,可以在不创建新子类的前提下,扩展对象的行为。但是,装饰器也带来代码复杂度上升的问题。使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。此外,装饰器模式比继承更加灵活,也同时意味着装饰器模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

代理模式

代理模式是一种结构型设计模式,用来为一个对象提供一种代理以控制对该对象的访问,即通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。代理对象控制着对于原对象的访问,并允许在将请求提交给原对象前后进行一些处理。为使用代理对象控制对原对象的访问,需要创建一个代理类并封装对原对象的访问。其类图表示如下:

请添加图片描述

代理模式适用于各种需要代理的场景,如远程代理、虚拟代理、缓存代理、动态代理等等。以动态代理为例,对于基于Spring框架开发的应用来说,Spring提供的AOP功能,可以看成是动态代理的一种应用。AOP通过切面的设计,可以在不影响对象的前提下,动态的增加代理完成对象的功能增加。
代理模式,在访问对象时引入了一定程度的间接性。因为可以在不对原对做出修改的情况下创建新代理,所以代理模式符合开闭原则。但代理模式的设计,也带来了代码复杂度上升的问题。实现代理模式需要额外的工作,有些代理模式的实现非常复杂(如动态代理)。此外,由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,从而带来服务响应的延迟。但是,这部分影响是极小的。
从类图结构上来说,装饰器模式和代理模式的相似度极高,但是两者还是有一定的差异。如果说装饰器模式的重心是动态地给对象增加一些职责模式,那么代理模式的重心则是通过代理对象间接地访问实际对象,并在代理过程中添加一些额外的逻辑或控制。代理模式主要应用于对象访问困难或复杂、或无法直接访问等场景。简言之,装饰器模式主要关注增强对象的功能,而代理模式则更多关注对对象访问的控制,并不直接增强对象的功能。

适配器模式

适配器模式是一种结构型设计模式,用于将一个类的接口转换成用户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器。根据适配器是根据继承方式,还是组合方式和待适配的类进行交互,可以将
适配器模式分为对象适配器和类适配器两种实现。对象适配器类图表示如下:

请添加图片描述

类适配器类图表示如下:

请添加图片描述

从类图结构上可以看到,对象适配器和类适配器的唯一差别就是适配器类(Adapter)和待适配类(Adaptee)的关系。对于类适配器来说,适配器类作为待适配类的子类,对原有方法进行了重写。而对于对象适配器来说,适配器类将待适配器类作为其成员,通过调用待适配器类的接口,完成了原有方法的重写。在实际的应用中,对于需要使用适配器的场景,应优先选用对象适配器。只有在对象适配器不合适的场景下,才考虑使用类适配器。如需要复用这样一些类,他们处于同一个继承体系,并且他们又有了额外的一些共同的方法,这时类适配器就比对象适配器更适合。
适配器模式主要适用于需要使用某个现有类,但是这个现有类的接口不符合系统的需要,或想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类一起工作等场景。适配器模式通过创建一个中间层类,可将其作为代码与遗留类、第三方类或提供接口的类之间的转换器。
适配器可以让接口不兼容的对象相互合作。通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码,实现了目标类和适配者类的解耦。且可以将接口或数据转换代码从目标类主要业务逻辑中分离出来,符合单一职责原则。但是,适配器模式也带来了代码整体复杂度上升的问题,开发者需要新增一系列接口和类。
适配器模式和装饰器模式都被称为包装器,但是两者适用的场合不同。适配器模式的主要目的是将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起协作。装饰器模式则是强调给对象增加一些新的行为或责任。适配器模式重点关注接口转换和兼容性,而装饰器模式则重点关注为对象动态地添加新的行为或责任。

装饰器模式、代理模式和适配器模式对比

无论装饰模式、代理模式和适配器模式,都是结构型设计模式。其主要职责都是将将类或对象按某种布局组成更大的结构,使得程序结构更加清晰。从类图结构上来说,装饰器模式和代理模式和对象适配器的结构上差异不大,都是通过一个外部类去组合目标类,并封装其行为。从功能上来说,装饰器模式关注的是给对象增加一些新的行为或责任。相比基于继承关系扩展对象的功能,装饰器模式可以提供比继承更多的灵活性,可以在不创建新子类的前提下,扩展对象的行为。代理模式更多的关注对象访问的控制,并不直接增强对象的功能。通过代理对象间接地访问实际对象,并在代理过程中添加一些额外的逻辑或控制。而适配器模式则关注接口转换或接口兼容性。通过将一个类的接口转换成客户端所期望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起协作。
在实际的应用中,针对装饰器模式、代理模式和适配器模式的选用上,还是要从功能上出发,因为三个设计模式在类图结构上差异并不大。通过其应用场景选择合适的设计模式,如对于对象功能增强的场景,选用装饰器模式,对于对象访问控制的场景,选用代理模式,对于接口的转换或兼容的场景,选用适配器模式。

参考

https://yiyan.baidu.com/ 文心一言
https://blog.csdn.net/kingmax54212008/article/details/107294704 OOAD-设计模式(四)结构型模式之适配器、装饰器、代理模式

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

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

相关文章

如何讲好ppt演讲技巧(4篇)

如何讲好ppt演讲技巧(4篇) 如何讲好PPT演讲技巧(四篇) **篇:精心准备,奠定演讲基础 一个成功的PPT演讲,离不开精心的准备。首先,要确定演讲的主题和目标,确保演讲内容清…

SpringMVC进阶(自定义拦截器以及异常处理)

文章目录 1.自定义拦截器1.基本介绍1.说明2.自定义拦截器的三个方法3.流程图 2.快速入门1.Myinterceptor01.java2.FurnHandler.java3.springDispatcherServlet-servlet.xml配置拦截器4.单元测试 3.拦截特定路径1.拦截指定路径2.通配符配置路径 4.细节说明5.多个拦截器1.执行流程…

七彩虹(Colorful)隐星P16 2023款笔记本电脑原装出厂Win11系统镜像下载 带建Recovery一键还原功能

七彩虹原厂Windows预装OEM专用系统,恢复出厂开箱状态一模一样 适用型号:隐星P16 23 链接:https://pan.baidu.com/s/1Ig5MQMiC8k4VSuCOZRQHUw?pwdak5l 提取码:ak5l 原厂W11系统自带所有驱动、出厂时自带的主题与专用壁纸、系…

第 4 篇 : Netty客户端互发图片和音/视频

说明 因为图片和音/视频不能确定其具体大小, 故引入MinIO。客户端之间只发送消息, 通过上传/下载来获取额外信息 1. MinIO搭建(参考前面文章), 并启动 2. 登录MinIO创建3个Bucket: image、voice、video 3. 客户端改造 3.1 修改 pom.xml <?xml version"1.0" …

浅谈OpenCV 粗略计算工件轮廓面积和外接圆直径(Emgu.CV)

前言 最近领导在做库房工具管理这块的功能&#xff0c;希望能集成OpenCV 粗略的计算出工具的长度&#xff0c;以方便用户再归还工具的时候&#xff0c;提示用户该放在那种尺寸的盒子里面&#xff0c;这便是这篇文章的由来。 我们的系统是基于.net开发的&#xff0c;所以采用的是…

Memory augment is All You Need for image restoration 论文翻译

目录 一.介绍 二.实际工作 A.图像阴影去除 B.图像去雨 C.存储模块的开发 三.网络结构 A.内存扩充 B.损失函数设计 四.实验 A.与最先进方法的比较 B.MemoryNet消融研究 五.结论 CVPR2023 MemoryNet 记忆增强是图像恢复所需要的一切 论文地址https://arxiv.org/abs/…

就业班 第三阶段(nginx) 2401--4.26 day5 nginx5 nginx https部署实战

三、HTTPS 基本原理 1、https 介绍 HTTPS&#xff08;全称&#xff1a;HyperText Transfer Protocol over Secure Socket Layer&#xff09;&#xff0c;其实 HTTPS 并不是一个新鲜协议&#xff0c;Google 很早就开始启用了&#xff0c;初衷是为了保证数据安全。 近些年&…

大型零售企业,适合什么样的企业邮箱大文件解决方案?

大型零售企业通常指的是在全球或特定地区内具有显著市场影响力和知名度的零售商。这些企业不仅在零售业务收入上达到了惊人的规模&#xff0c;而且在全球范围内拥有广泛的销售网络和实体店铺。它们在快速变化的零售行业中持续创新&#xff0c;通过实体店、电商平台等多种渠道吸…

「C++ 内存管理篇 1」C++动态内存分配

目录 〇、C语言的动态内存分配方式 一、C的动态内存分配方式 1. 什么是C的动态内存分配&#xff1f; 2. 为什么需要C的动态内存分配&#xff1f; a. new的优势 b. new的不足 c. delete的优势 d. 总结 3. 怎么使用new和delete? a. 对于内置类型 b. 对于自定义类型 c. 为什么ne…

python学习笔记----循环语句(四)

一、while循环 为什么学习循环语句 循环在程序中同判断一样&#xff0c;也是广泛存在的&#xff0c;是非常多功能实现的基础&#xff1a; 1.1 while循环语法 while 条件表达式:# 循环体# 执行代码这里&#xff0c;“条件表达式”是每次循环开始前都会评估的表达式。如果条件…

【血泪教训】Altium Designer隐藏覆铜层导致PCB电路板未加工隐藏层

Altium Designer隐藏覆铜层导致PCB电路板未加工隐藏层 血泪教训&#xff01;&#xff01;&#xff01; 事情经过是这样的 测试板PCB Layout完成后&#xff0c;隐藏铺铜层&#xff0c;方便check&#xff0c;隐藏操作如下图所示&#xff0c;选择“隐藏所有”或“隐藏选中铺铜”…

Redis基本數據結構 ― String

Redis基本數據結構 ― String 介紹常用命令範例1. 為字串鍵設值/取得字串鍵的值2. 查看字串鍵的過期時間3. 如何為key設置時間?4. 如何刪除指定key?5. 如何增加value的值?6. 獲取value值的長度 介紹 字串鍵是Redis中最基本的鍵值對類型&#xff0c;這種類型的鍵值對會在數據…

【python技术】使用akshare抓取东方财富所有概念板块,并把指定板块概念的成分股保存excel 简单示例

最近有个想法&#xff0c;分析A股某个概念成分股情况进行分析&#xff0c;第一反应是把对应概念板块的成分股爬取下来。说干就干 下面是简单示例 import akshare as ak import pandas as pddef fetch_and_save_concept_stocks(name):# 获取指定股票概念的成分股&#xff0c;并…

机器学习每周挑战——百思买数据

最近由于比赛&#xff0c;断更了好久&#xff0c;从五一开始不会再断更了。这个每周挑战我分析的较为简单&#xff0c;有兴趣的可以将数据集下载下来试着分析一下&#xff0c;又不会的我们可以讨论一下。 这是数据集&#xff1a; import pandas as pd import numpy as np impo…

Leetcode-面试题 02.02. 返回倒数第 k 个节点

目录 题目 图解 代码 面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/description/ 题目 实现一种算法&#xff0c;找出单向链表中倒数第 k 个节点。返回该节点的值。 注意&…

保证接口幂等性的多种实现方式(数据库方案)

1. 幂等性的概念 接口幂等性是指在软件工程和Web服务领域中&#xff0c;一个接口&#xff08;通常是HTTP API&#xff09;无论被调用一次还是多次&#xff0c;其对系统产生的副作用应该是相同的&#xff0c;即结果保持一致&#xff0c;不会因为多次请求而有所不同。换句话说&am…

ES练习项目-酒店搜索

目录 1 需求分析2 酒店搜索和分页2.1 请求和响应分析2.2 定义实体类&#xff0c;接收请求参数的JSON对象2.3 编写controller&#xff0c;接收页面的请求2.4 编写业务实现&#xff0c;利用RestHighLevelClient实现搜索、分页 3. 酒店结果过滤3.1 请求和响应分析3.2 修改请求参数…

上位机图像处理和嵌入式模块部署(树莓派4b设置ftp下载)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 作为一个开发板&#xff0c;最好支持ftp下载&#xff0c;这样文件的上传和下载都会比较方便。虽然目前为止&#xff0c;利用mobaxterm和ssh也能实现…

算法学习(5)-图的遍历

目录 什么是深度和广度优先 图的深度优先遍历-城市地图 图的广度优先遍历-最少转机 什么是深度和广度优先 使用深度优先搜索来遍历这个图的过程具体是&#xff1a; 首先从一个未走到过的顶点作为起始顶点&#xff0c; 比如以1号顶点作为起点。沿1号顶点的边去尝试访问其它未…

用Jenkins实现cherry-pick多个未入库的gerrit编译Android固件

背景: 在做Android固件开发的时候,通常我们可以利用gerrit-trigger插件,开发者提交一笔的时候自动触发jenkins编译,如果提交的这一笔的编译依赖其他gerrit才能编译过,我们可以在commit message中加入特殊字段,让jenkins在编译此笔patch的时候同时抓取依赖的gerrit代码下…