【设计模式】结构型设计模式之 从IO流设计思想来看装饰器模式

news2024/11/12 12:05:50

介绍

装饰器模式也称为包装模式(Wrapper Pattern) 是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。
装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。

装饰器模式代码举例

实现逻辑

  1. 装饰器类和原始类实现共同的父类,下方案例中的 Coffe
  2. 装饰器类,组合原始类的对象作为目标对象
  3. 装饰器类重写需要装饰的方法,并且重写的内容中可以调用原始类的对象方法。
  4. 通过中间层的装饰器基类,避免实现每个共同父类的方法

代码

//装饰器和目标类基础接口
public interface Coffee {
    String getDescription();
    double getCost();
}

//具体的咖啡,什么都不加
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }

    @Override
    public double getCost() {
        return 1.0;
    }
}

//装饰器基类,为了避免每个装饰器都要手动重新实现共同父类的接口,即使该装饰器不需要装饰对应方法
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

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

    @Override
    public abstract String getDescription();

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

//摩卡咖啡装饰器,增加风味描述、增加价格
public class MochaDecorator extends CoffeeDecorator {
    public MochaDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Mocha";
    }

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

//奶油装饰器,增加奶油、增加价格
public class WhipDecorator extends CoffeeDecorator {
    public WhipDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Whip";
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.3;
    }
}


//测试类
public class Main {
    public static void main(String[] args) {
        // 创建一杯简单的咖啡
        Coffee simpleCoffee = new SimpleCoffee();
        
        // 添加摩卡装饰
        Coffee mochaCoffee = new MochaDecorator(simpleCoffee);
        
        // 再添加奶泡装饰
        Coffee finalCoffee = new WhipDecorator(mochaCoffee);
        
        System.out.println(finalCoffee.getDescription() + " costs $" + finalCoffee.getCost());
    }
}


Simple Coffee, Mocha, Whip costs $1.8

IO 类库的装饰器模式

为什么没有 BufferdFileInputStream

在 JAVA 的 IO 类库中,例如如果让 FileInputStream 支持 BufferdInputStream,需要让 需要间接的将 FileInputStream 传递给 BufferdInputStream。为什么 Java 不直接支持BufferdFileInputStream 呢。

InputStream in = new FileInputStream("");
InputStream bin = new BufferedInputStream(in);

为什么不基于继承实现 BufferedFileInputStream

  1. 如果 InputStream 类只有一个子类 FileInputStream 那么再在 FileInputStream 下面实现一个BufferedInputStream 也没有什么问题
  2. 问题在于 InputStream 的子类太多了,如果每个子类都单独实现 Buffered 功能和 DataInputStream 的功能那么类的数量将会爆炸性增多。

IO 类库使用装饰模式实现

  1. 在设计原则中,组合优于继承,针对继承结构过于复杂的问题可以将继承关系转换为组合关系来解决。
  2. 所以 IO 类库中,对于 BufferedInputStream 没有选择对所有的 InputStream 实现一遍,而是只实现一遍通过组合目标 InputStream 来实现增强功能
  3. 对于需要实现 Buffered 的功能的 inputStream,只需使用BufferedInputStream 对其进行一次包装即可实现。
  4. 并且如果想要实现 DataInputStream 的按照数据类型读取,只需要再次添加一层包装即可。

总结&思考

总结

  1. 装饰器模式可以解决继承关系过于复杂的问题,通过组合关系替代继承关系。
  2. 装饰器模式主要的作用是给原始类添加增强功能,除此之外装饰器模式还支持嵌套使用,为了满足这个功能装饰器类和原始类都继承自相同的父类或者接口。
  3. 装饰器模式和静态代理模很相似,都是通过组合来对原始类进行增强,主要区别是代理模式主要对原始类不相关的功能进行增强,但是装饰器模式是对原始类相关功能的增强。

IO 类库的 FilterInputStream 的作用是什么

  1. 和案例中的装饰类基类作用一样,提供 InputStream 需要实现的方法的实现。方法的具体执行通过委托给组合的 InputStream 对象实现。
  2. 如果没有 FilterInputStream,那么每个装饰器类,都需要对 InputStream 的方法提供实现,即使是委托给组合的 InputStream 成员对象执行也会很麻烦。

装饰器类和原始类有相同的父类的作用

装饰器类和原始类有相同的父类,例如 InputStream 和 Coffee 可以实现对原始类进行“嵌套”多个装饰器类来进行增强。例如对 FileInputStream 包装 BufferedInputStream 后再包装一层 DataInputStream,这样既实现了缓存读取又实现类按照基本数据类型来读取。

和其他组合代替继承的设计模式(例如代理模式)的区别

代理模式中,代理类附加的是原始类不相关的功能,但是装饰器模式中附加的是与原始类相关的增强功能。

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

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

相关文章

Java | Leetcode Java题解之第142题环形链表II

题目: 题解: public class Solution {public ListNode detectCycle(ListNode head) {if (head null) {return null;}ListNode slow head, fast head;while (fast ! null) {slow slow.next;if (fast.next ! null) {fast fast.next.next;} else {ret…

Qt qtpropertybrowser使用实例(1)

属性界面实例&#xff1a; 代码如下&#xff1a; #include <QDate> #include <QLocale> #include "qtpropertymanager.h" #include "qtvariantproperty.h" #include "qttreepropertybrowser.h" int main(int argc, char *argv[]) {…

LLM大语言模型(十六):最新开源 GLM4-9B 本地部署,带不动,根本带不动

目录 前言 本机环境 GLM4代码库下载 模型文件下载&#xff1a;文件很大 修改为从本地模型文件启动 启动模型cli对话demo 慢&#xff0c;巨慢&#xff0c;一个字一个字的蹦 GPU资源使用情况 GLM3资源使用情况对比 前言 GLM-4-9B 是智谱 AI 推出的最新一代预训练模型 …

VUE + nodejs实战

BVDN搭建 D: cd nodejs ::npm install bootstrap ::npm install jquery ::npm install popper.js ::npm install vue npm install vue-router pauseapp.html <!DOCTYPE html> <!DOCTYPE html> <html> <head><!--bootstrap--><link rel"…

Understanding Diffusion Objectives as the ELBO with Simple Data Augmentation

Understanding Diffusion Objectives as the ELBO with Simple Data Augmentation 引言 本文前作 VDM 已经推导出了扩散模型可以将优化 ELBO 作为目标函数。然而现在 FID &#xff08;也就是感知质量&#xff09;最好的模型还是用的其他目标函数&#xff08;如 DDPM 的噪声预…

Mysql使用中的性能优化——索引数对插入操作性能的影响

表的索引可以给数据检索提升效率&#xff0c;但是也给表的增删改操作带来代价。本文我们将关注&#xff0c;索引数量对INSERT操作的影响。 结论 索引数的新增会造成INSERT操作效率下降&#xff0c;约每增一个索引会降低10%效率。 实验数据 可以看到0个索引的效率是7个索引效…

【Linux】 安装rz 和sz

在 Linux 系统中&#xff0c;rz 和 sz 是两个用于在本地计算机与远程计算机之间安全传输文件的命令行工具。它们是 lrzsz 包的一部分&#xff0c;通常用于通过 SSH 连接传输文件。 打开终端&#xff1a; 首先&#xff0c;打开你的 CentOS 机器上的终端。 执行sz 提示下面信息…

【数据结构(邓俊辉)学习笔记】图05——优先级搜索

文章目录 0. 概述1. BAG2. ADT 0. 概述 学习下优先级搜索 1. BAG 优先级搜索是非常广义的&#xff0c;概况来说&#xff0c;无论DFS 还是BFS从逻辑上来都属于这种搜索。 回忆下什么叫搜索或者遍历&#xff0c;对于像图这种数据结构里的元素逐一的没有重复的也没有遗漏的对它们…

开发uniapp 小程序时遇到的问题

1、【微信开发者工具报错】routeDone with a webviewId XXX that is not the current page 解决方案: 在app.json 中添加 “lazyCodeLoading”: “requiredComponents” uniapp的话加到manifest.json下的mp-weixin 外部链接文章&#xff1a;解决方案文章1 解决方案文章2 &qu…

vs2019 c++20规范 全局函数 ref 及模板类 reference_wrapper<_Ty> 的源码分析

这是个引用&#xff0c;可以包裹一个对象&#xff0c;相当于引用该对象&#xff0c;而不是在作为函数形参时产生值传递。因为模板 reference_wrapper<_Ty> 其实是封装了该对象的地址。下面以图示形式给出其重要的成员函数。模板其实都差不多&#xff0c;跟人也一样&#…

使用Redis的优势以及会引发的问题

优势 ①使用redis代表着高性能还有高并发&#xff0c;高性能很好理解&#xff0c;redis会缓存我们访问的数据。他是基于内存的&#xff0c;第一次访问数据库我们可能需要800ms&#xff0c;但是访问后如果使用redis进行缓存&#xff0c;第二次乃至后面访问相同的数据就只需要去…

Flutter基础 -- Dart 语言 -- 进阶使用

目录 1. 泛型 generics 1.1 泛型使用 1.2 泛型函数 1.3 构造函数泛型 1.4 泛型限制 2. 异步 async 2.1 异步回调 then 2.2 异步等待 await 2.3 异步返回值 3. 生成器 generate &#xff08;了解&#xff09; 3.1 同步生成器 sync* 使用 sync* 的场景 总结 3.2 异…

软件项目调研三部曲(调研计划,调研大纲,调研报告)原件获取

软件项目详细调研的目的是依据项目合同的要求&#xff0c;能够通过在客户现场&#xff0c;并通过访谈的方式&#xff0c;尽可能的了解客户的需求和业务现状&#xff0c;包括客户涉及到的业务部门的岗位设置、岗位职责、工作内容、工作流程、管理难点以及通过实施信息化系统的期…

Silanna UV光荣推出了一款革命性的高功率远紫外线LED

这款令人瞩目的光源&#xff0c;拥有令人震撼的235nm波长&#xff0c;并被巧妙地封装在紧凑的6.8mm结构中&#xff0c;其魅力与实力兼具。 今年六月&#xff0c;在苏格兰圣安德鲁斯大学举行的盛大2024年远紫外科学和技术国际大会&#xff08;ICFUST&#xff09;上&#xff0c;S…

深度剖析AI机会,数字人智能对话系统:未来的人机交互新范式

Datawhale干货 作者&#xff1a;邓恺俊&#xff0c;Datawhale成员 随着人工智能时代的到来&#xff0c;大模型的技术日新月异&#xff0c;我们不仅仅满足于文字之间的交互&#xff0c;希望能够有更近一步的交流。既然现在文字已经能够很好的模拟人类了&#xff0c;那随之而来的…

牛客网刷题 | BC120 争夺前五名

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 期中考试开始了&am…

基于非下采样小波包分析的滚动轴承故障诊断(MATLAB R2021B)

小波变换具有良好的时频局部化特性和多分辨率特性&#xff0c;可准确定位信号的突变点并可在不同尺度上描述信号的局部细节特征&#xff0c;被广泛应用于信号降噪。但标准正交小波变换不具有平移不变性&#xff0c;采用标准正交小波对信号消噪后&#xff0c;会在脉冲尖峰处产生…

Dubbo 3.x源码(21)—Dubbo服务引用源码(4)

基于Dubbo 3.1&#xff0c;详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了createInvokerForRemote方法中的Wrapper有哪些以及作用&#xff0c;接下来我们将会的学习真正的本地、应用级别、接口级别的Protocol的引入逻辑&#xff0c;以及创建Proxy服务接口代理对象的逻…

UI学习的案例——照片墙

照片墙案例 在实现照片墙案例之前先讲一下userInteractionEnable这个属性。 首先这个属性属于UIView&#xff0c;这个属性是bool类型&#xff0c;如果为YES的话&#xff0c;这个UIView会接受有关touch和keyboard的相关操作&#xff0c;然后UIView就可以通过相应的一些方法来处…

Hive日志介绍

日志描述 日志路径&#xff1a;Hive相关日志的默认存储路径为“/var/log/Bigdata/hive/角色名”&#xff0c;Hive1相关日志的默认存储路径为“/var/log/Bigdata/hive1/角色名”&#xff0c;以此类推。 HiveServer&#xff1a;“/var/log/Bigdata/hive/hiveserver”&#xff0…