结构型设计模式(二)装饰器模式 适配器模式

 

6b6fa1c626f5a61327c21c861ed353cb.png

装饰器模式 Decorator

1、什么是装饰器模式

装饰器模式允许通过将对象放入特殊的包装对象中来为原始对象添加新的行为。这种模式是一种结构型模式,因为它通过改变结构来改变被装饰对象的行为。它涉及到一组装饰器类,这些类用来包装具体组件。

2、为什么使用装饰器模式

  1. 灵活性:装饰器模式允许在运行时动态地为对象添加新的行为,而无需修改其代码,提供了一种灵活的方式来扩展对象的功能。
  2. 避免子类爆炸:通过使用装饰器模式,可以避免创建大量子类来扩展对象的功能,从而避免了子类爆炸的问题。
  3. 组合功能:可以通过组合多个装饰器来实现复杂的功能组合,无需使用大量的继承关系。

3、如何使用装饰器模式

设计实现咖啡订单系统,包含基本咖啡和不同的配料作为装饰器

// 抽象组件 - 咖啡
interface Coffee {
    String getDescription();
    double cost();
}

// 具体组件 - 基本咖啡
class BasicCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Basic Coffee";
    }

    @Override
    public double cost() {
        return 3.0;
    }
}

// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }
}

// 具体装饰器 - 牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Milk";
    }

    @Override
    public double cost() {
        return super.cost() + 1.0;
    }
}

// 具体装饰器 - 糖
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Sugar";
    }

    @Override
    public double cost() {
        return super.cost() + 0.5;
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建基本咖啡
        Coffee basicCoffee = new BasicCoffee();
        System.out.println("Description: " + basicCoffee.getDescription());
        System.out.println("Cost: $" + basicCoffee.cost());

        // 添加牛奶装饰器
        Coffee milkCoffee = new MilkDecorator(basicCoffee);
        System.out.println("Description: " + milkCoffee.getDescription());
        System.out.println("Cost: $" + milkCoffee.cost());

        // 添加糖装饰器
        Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
        System.out.println("Description: " + sugarMilkCoffee.getDescription());
        System.out.println("Cost: $" + sugarMilkCoffee.cost());
    }
}

4、是否存在缺陷和不足

  1. 可能导致类爆炸:有大量具体组件和装饰器时,可能导致类的数量急剧增加,增加了系统的复杂性。
  2. 破坏封装性:装饰器模式将具体组件暴露给装饰器类,可能破坏了封装性。

5、如何缓解缺陷和不足

  1. 使用抽象工厂:结合抽象工厂模式,通过工厂来创建组件和装饰器,降低类的数量。
  2. 使用组合模式:将具体组件和装饰器组织成树形结构,使用组合模式来管理它们的关系。
  3. 慎用过多装饰器:在设计时慎用过多的装饰器,确保仅在需要时使用,以避免类爆炸问题。

适配器模式 Adapter

1、什么是适配器模式

适配器模式允许原本由于接口不匹配而无法在一起工作的类能够协同工作。它通过引入一个包装类,即适配器,来转换原有类的接口为客户端期望的接口。

2、为什么使用适配器模式

  1. 解耦性:适配器模式允许客户端与目标类的实现细节解耦,使得客户端不需要知道目标类的内部实现。
  2. 复用性:适配器模式可以使得已有的类在新的系统中复用,而无需修改其代码。
  3. 灵活性:适配器模式允许在不改变现有代码的情况下引入新的类,提高系统的灵活性。

3、如何使用适配器模式

// 目标接口
interface Target {
    void request();
}

// 不兼容的类
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specificRequest");
    }
}

// 适配器类
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();
    }
}

4、是否存在缺陷和不足

  1. 可能导致过多的适配类:如果系统中有多个不同的类需要适配,可能会导致大量的适配器类,使系统变得复杂。
  2. 不支持多继承的语言的限制:在一些不支持多继承的语言中,适配器模式可能会受到限制。

5、如何缓解缺陷和不足

  1. 使用对象适配器而非类适配器:对象适配器通过组合的方式引入被适配对象,避免了类适配器的多继承问题。
  2. 考虑使用接口适配器:如果目标接口中定义的方法较多,可以考虑使用接口适配器模式,只需实现感兴趣的方法。

 

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

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

相关文章

带PWM 调光的线性降压 LED 恒流驱动器

一、基本概述 TX6410B是一种带 PWM 调光功能的线性降压 LED 恒流驱动器,仅需外接一个电阻就可以构成一个完整的 LED 恒流驱动电路,调节该外接电阻可调节输出电流,输出电流范围为 10~2000mA。TX6410B内置 30V 50 毫欧 MOS。TX6410B内置过热保…

机器学习 | 决策树 Decision Tree

—— 分而治之,逐个击破 把特征空间划分区域 每个区域拟合简单模型 分级分类决策 1、核心思想和原理 举例: 特征选择、节点分类、阈值确定 2、信息嫡 熵本身代表不确定性,是不确定性的一种度量。 熵越大,不确定性越高,…

IDEA2023 + spring cloud 工程热部署设置方法

基于spring cloud 工程进行热部署 &#xff0c;实现每次修改工程源文件&#xff0c;后台自动启动&#xff0c;方便开发测试工作。具体分为5步骤即可&#xff1a; 1、修改工程的pom文件&#xff0c;增加adding devtools 工具包。 <dependency> <groupId>org.s…

olap/clickhouse-编译器优化与向量化

本文主要结合15721和clickhouse源码来聊聊向量化&#xff0c;正好我最近也在用Eigen做算子加速&#xff0c;了解下还是有好处的。 提示编译器 提示编译器而不是复杂化简单的代码 什么时候使用汇编&#xff0c;什么时候使用SIMD&#xff1f;下面有几个基本原则&#xff1a; …

用23种设计模式打造一个cocos creator的游戏框架----(十九)备忘录模式

1、模式标准 模式名称&#xff1a;备忘录模式 模式分类&#xff1a;行为型 模式意图&#xff1a;在不破坏封装性的前提下捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态 结构图&#xff1a; 适用于&#xff1a; …

DMA传输中的中断处理在STM32中的应用

DMA&#xff08;Direct Memory Access&#xff09;是一种在数字系统中进行数据传输的技术&#xff0c;它可以在不依赖CPU的情况下直接从内存中读取或写入数据。在STM32微控制器中&#xff0c;DMA控制器可以与外设进行数据传输&#xff0c;减轻了CPU的负担&#xff0c;提高了数据…

DFT音频还原及降噪实战

傅里叶变换与信息隐写术(二) 声音数据 ​ 声音可以用连续的波形来表示 ​ 声音在计算机中的存储是离散的 ​ 计算机中存储的是声音的几个采样点的数据&#xff0c;1 秒钟采样 5 个点就表示采样频率是 5 Hz&#xff08;每隔 0.25 秒取一个点&#xff0c;注意第 0 秒也取&#…

python:import自定义包或py文件时,pyCharm正常但终端运行提示ModuleNotFoundError: No module named错误

问题 示例项目引用items.py&#xff0c;项目在pycharm开发工具中可以正常运行&#xff0c;但使用终端直接运行会报错ModuleNotFoundError: No module named。如下图。 原因 pycharm开发工具运行正常&#xff0c;说明目录和引用模块是没问题的。问题在于终端的运行环境只搜索文…

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

目录 一、双向链表的概念 二、 双向链表的优缺点分析​与对比 2.1双向链表特点&#xff1a; 2.2双链表的优劣&#xff1a; 2.3循环链表的优劣 2.4 顺序表和双向链表的优缺点分析​ 三、带头双向循环链表增删改查实现 3.1SList.c 3.2创建一个新节点、头节点 3.3头插 3.…

手拉手EasyExcel极简实现web上传下载(全栈)

环境介绍 技术栈 springbootmybatis-plusmysqleasyexcel 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 1.8 Spring Boot 2.7.13 mybatis-plus 3.5.3.2 EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性…

华为鸿蒙应用--欢迎页SplashPage+倒计时跳过(自适应手机和平板)-ArkTs

鸿蒙ArkTS 开发欢迎页SplashPage倒计时跳过&#xff0c;可自适应平板和手机&#xff1a; 一、SplashPage.ts import { BreakpointSystem, BreakPointType, Logger, PageConstants, StyleConstants } from ohos/common; import router from ohos.router;Entry Component struct…

数据结构之<树>的介绍

树的基本概念 在数据结构中&#xff0c;树&#xff08;Tree&#xff09;是一种层次结构&#xff0c;由节点和边组成。树的基本概念包括根节点、子节点、父节点、兄弟节点等。节点拥有零个或多个子节点&#xff0c;除了根节点外&#xff0c;每个节点有且仅有一个父节点。树的层…

数据结构-猴子吃桃问题

一、需求分析 有一群猴子摘了一堆桃子&#xff0c;他们每天都吃当前桃子的一半且再多吃一个&#xff0c;到了第10天就只余下一个桃子。用多种方法实现求出原来这群猴子共摘了多少个桃子。要求&#xff1a; 1)采用数组数据结构实现上述求解&#xff1b; 2)采用链数据结构实现上述…

13、Kafka副本机制详解

Kafka 副本机制详解 1、副本定义2、副本角色3、In-sync Replicas&#xff08;ISR&#xff09;4、Unclean 领导者选举&#xff08;Unclean Leader Election&#xff09; 所谓的副本机制&#xff08;Replication&#xff09;&#xff0c;也可以称之为备份机制&#xff0c;通常是指…

离线编译安装opencv库及多版本切换[ubuntu]

系统版本&#xff1a;ubuntu18.04 库版本&#xff1a;opencv4.6.0 & opencv3.6.0 一、多版本安装前准备 1. 卸载已经安装的opencv版本[可选] 1.1 卸载从软件仓库中安装的opencv sudo apt-get purge libopencv* 1.2 卸载使用source自行编译安装的opencv 首先进入原先编译…

人生感悟 | 又是一年,眼看要2024了

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 刚过完大雪节气没两天&#xff0c;气温开始急转直下&#xff0c;走在路上明显感觉冷了许多。看天气预报很多地区已经开始下雪了。 看日历已经12月9号了&#xff0c;12月份&#xff0c;一年的最后一个月&#xff0c;2…

自然语言处理阅读第二弹

HuggingFace 镜像网站模型库 NLP中的自回归模型和自编码模型 自回归&#xff1a;根据上文内容预测下一个可能的单词&#xff0c;或者根据下文预测上一个可能的单词。只能利用上文或者下文的信息&#xff0c;不能同时利用上文和下文的信息。自编码&#xff1a;对输入的句子随…

【TB作品】STM32 PWM之实现呼吸灯,STM32F103RCT6,晨启

文章目录 完整工程参考资料实验过程 实验任务&#xff1a; 1&#xff1a;实现PWM呼吸灯&#xff0c;定时器产生PWM&#xff0c;控制实验板上的LED灯亮灭&#xff1b; 2&#xff1a;通过任意两个按键切换PWM呼吸灯输出到两个不同的LED灯&#xff0c;实现亮灭效果&#xff1b; 3&…

FRP 内网穿透工具部署

FRP 介绍 frp 是一个专注于内网穿透的高性能反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 官方网站&#xff1a;https://gofrp.org/zh-cn/ 项目地…

ARS430毫米波雷达标定步骤

工具准备&#xff1a;CANoe&#xff0c; 标定工程文件&#xff0c;雷达标定板&#xff0c;三脚架&#xff0c;激光器&#xff0c;平口钳&#xff0c;气泡水平仪&#xff0c;小镜子&#xff0c;双面胶。 将车辆放置在车辆前方至少有20米空白视野的场地上。使用气泡水平仪大概使…