设计模式之适配器与装饰器

目录

适配器模式

简介

角色

使用

优缺点

使用场景

装饰器模式

简介

优缺点

模式结构

使用

使用场景


适配器模式

简介

允许将不兼容的对象包装成一个适配器类,使得其他类可以通过适配器类与原始对象进行交互,从而提高兼容性

角色

目标角色:该角色定义把其他类转换为何种接口,也就是我们的期望接口

源角色:你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象

适配器角色:适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:通过继承或是类关联的方式把源角色转换为目标角色

使用

1.定义目标接口:创建一个目标接口,这个接口定义了客户端所期望的功能。

2.创建原始类:客户端原始功能

3.创建适配器类:创建一个适配器类,该类实现了目标接口,同时包装了不兼容的原始对象,使得客户端可以通过目标接口与原始对象进行交互

4.使用目标接口:客户端代码使用目标接口与适配器进行交互

// 目标接口  
interface Target {  void request();  
}  // 原始类  
class Adaptee {  void specificRequest() {  System.out.println("Adaptee's specific request.");  }  
}  // 适配器类  
class Adapter implements Target {  private Adaptee adaptee;  public Adapter(Adaptee adaptee) {  this.adaptee = adaptee;  }  @Override  public void request() {  adaptee.specificRequest();  }  
}  // 客户端代码  
public class Client {  public static void main(String[] args) {  Adaptee adaptee = new Adaptee();  Target target = new Adapter(adaptee);  target.request();  }  
}

        目标接口Target,它定义了一个request方法。我们还有一个原始类Adaptee,它有一个名为specificRequest的方法。我们的适配器类Adapter实现了目标接口,并且包装了原始类的specificRequest方法。在客户端代码中,我们创建了一个原始类的实例和一个适配器类的实例,然后将适配器类的实例传递给目标接口的引用。当我们调用目标接口的request方法时,实际上是适配器类在调用原始类的specificRequest方法

优缺点

优点:

        1.能提高类的透明性和复用,现有的类复用但不需要改变。

        2.目标类和适配器类解耦,提高程序的扩展性。

        3.在很多业务场景中符合开闭原则

缺点:

        1.适配器编写过程需要全面考虑,可能会增加系统的复杂性

        2.增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱

使用场景

        1.一个类的接口转换成期望的另一个接口,使不能兼容的两个类一起工作

        2.想要创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作

        3.在软件维护期间,由于不同产品或不同厂家造成功能类似而接口不相同的情况,可以通过适配器模式来解决

        使用适配器模式可以降低不同组件之间的耦合度,提高系统的可扩展性和可维护性。同时,适配器模式还可以解决不同系统之间的接口不兼容问题

装饰器模式

简介

        在不改变现有对象结构下,动态的给对象添加一些功能

优缺点

优点

        1.装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用

        2.通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果

        3.装饰器模式完全遵守开闭原则

缺点

        装饰器模式会增加许多子类,过度使用会增加程序得复杂性

模式结构

角色:

        抽象构件角色:定义一个抽象接口以规范准备接收附加责任的对象

        具体构件角色:实现抽象构件,通过装饰角色为其添加一些职责

        抽象装饰角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能

        具体装饰角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任

结构图:

使用

1.创建接口

public interface Shape {  double getArea();  
}

2.接口具体实现类

public class Rectangle implements Shape {  private double length;  private double width;  public Rectangle(double length, double width) {  this.length = length;  this.width = width;  }  @Override  public double getArea() {  return length * width;  }  
}

3.创建抽象装饰器

public abstract class ShapeDecorator implements Shape {  protected Shape decoratedShape;  public ShapeDecorator(Shape shape) {  this.decoratedShape = shape;  }  @Override  public double getArea() {  return decoratedShape.getArea();  }  
}

4.创建具体装饰器

public class RectangleWithBorder extends ShapeDecorator {  private double borderWidth;  public RectangleWithBorder(Shape shape, double borderWidth) {  super(shape);  this.borderWidth = borderWidth;  }  @Override  public double getArea() {  return decoratedShape.getArea() + borderWidth * decoratedShape.getArea();  }  
}

5.使用

public class Main {  public static void main(String[] args) {  Shape rectangle = new Rectangle(5, 5);  Shape rectangleWithBorder = new RectangleWithBorder(rectangle, 1); // 给矩形添加边框宽度为1的装饰器  System.out.println("Rectangle area: " + rectangle.getArea()); // 输出:Rectangle area: 25.0  System.out.println("Rectangle with border area: " + rectangleWithBorder.getArea()); // 输出:Rectangle with border area: 27.0  }  
}

使用场景

1.扩展功能:当您想要扩展一个类的功能时,可以使用装饰器模式来添加新的责任,而不需要修改原有类的代码。这使得代码更加灵活,易于维护

2.动态变化:如果需要在运行时根据需要动态地改变对象的行为,可以使用装饰器模式

3.统一接口:如果有一组具有相似功能但是又不完全相同的类,可以使用装饰器模式来统一它们的接口,使得在使用它们时不需要关心具体的类

4.延迟加载:如果某些数据是可选的,可以在需要时才加载,使用装饰器模式可以实现延迟加载的功能

5.处理复杂对象:当涉及到复杂的对象结构时,装饰器模式可以简化代码。通过将不同的行为封装到不同的装饰器中,可以组合这些装饰器来创建具有不同行为的对象

        装饰器模式适用于在不修改原有代码的基础上,动态地给对象添加新的行为。它适用于需要在运行时动态地改变对象行为或者需要统一接口的场景。

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

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

相关文章

Linux--进程--创建子进程一般目的

父进程创建子进程的目的:简单来说:给特定的输入,给出特定的输出 父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当请求到达,父进程调用fork&…

操作系统强化认识之Shell编程学习与总结

目录 1.Shell的概述 2.Shell脚本入门 3.变量 3.1.系统预定义变量 3.2.自定义变量 3.3.特殊变量 4.运算符 5.条件判断 6.流程控制 6.1.if判断 6.2.case语句 6.3.for循环 6.4.while循环 7.read读取控制台输入 8.函数 8.1.系统函数 8.2.自定义函数 9.正则表示式入…

Upload-labs 1~15 通关详细教程

文章目录 Upload-labs 1~15 通关详细教程Pass-01-前端js验证Pass-02-后端MIME验证Pass-03-黑名单验证Pass-04-黑名单验证.htaccessPass-05-文件后缀名大小写绕过Pass-06-文件后缀名空格绕过Pass-07-文件后缀名点绕过Pass-08-文件后缀名::$DATA绕过Pass-09-点空格点空格绕过Pass…

Unity(三) Shader着色器初探

学习3D开发技术的时候无可避免的要接触到Shader,那么Shader是个什么概念呢?其实对于开发同事来说还是比较难理解的,一般来说Shader是服务于图形渲染的一类技术,开发人员可以通过其shader语言来自定义显卡渲染页面的算法&#xff0…

KMP超高效匹配算法

简介: KMP算法是一种改进的字符串匹配算法,其中,KMP算法的运用核心是利用匹配失败后的信息,最大进度的减少模式串与目标串的匹配次数以达到快速匹配的效果。算法与暴力求解的改进在于每当一趟匹配过程中出现的字符比较不相等时&am…

文件包含漏洞学习小结

目录 一、介绍 二、常见文件包含函数 三、文件包含漏洞代码举例分析 四、文件包含漏洞利用方式 4.1 本地文件包含 1、读取敏感文件 2、文件包含可运行的php代码 ①包含图片码 ②包含日志文件 ③包含环境变量getshell ④临时文件包含 ⑤伪协议 4.2 远程文件包含 4.…

Ubuntu18.04安装docker-io

1. 安装docker 1.1 网上一搜,全是更新仓库、下载依赖、添加docker的gpg密钥、添加docker仓库、安装docker-ce的步骤,但是在安装docker-ce时却提示“package "docker-ce" has no installation candidate”,就很迷。 1.2 安装docke…

CH341 USB总线转接芯片

产品概述: CH341是一个USB总线的转接芯片,通过USB总线提供异步串口、打印口、并口以及常用的2线和4线等同步串行接口。 在异步串口方式下,CH341提供串口发送使能、串口接收就绪等交互式的速率控制信号以及常用的MODEM联络信号,用于…

插入排序(Insertion Sort)

C自学精简教程 目录(必读) 插入排序 每次选择未排序子数组中的第一个元素&#xff0c;从后往前&#xff0c;插入放到已排序子数组中&#xff0c;保持子数组有序。 打扑克牌&#xff0c;起牌。 输入数据 42 20 17 13 28 14 23 15 执行过程 完整代码 #include <iostream…

es6解构用法

一: 解构数组 二&#xff1a;解构对象 一: 解构数组 原理&#xff1a;模式(结构匹配), 索引值相同的完成赋值 总结&#xff1a;位置对应 二&#xff1a;解构对象 原理&#xff1a;模式(结构匹配), 属性名相同的完成赋值 {}{} 对象结构赋值的应用 常用的就以上两种 &#…

从零开始学习 Java:简单易懂的入门指南之查找算法及排序算法(二十)

查找算法及排序算法 常见的七种查找算法&#xff1a;1. 基本查找2. 二分查找3. 插值查找4. 斐波那契查找5. 分块查找6. 哈希查找7. 树表查找 四种排序算法&#xff1a;1. 冒泡排序1.1 算法步骤1.2 动图演示1.3 代码示例 2. 选择排序2.1 算法步骤2.2 动图演示 3. 插入排序3.1 算…

stable diffusion实践操作-hypernetworks

系列文章目录 本文专门开一节写hypernetworks的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、h…