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

2024-06-10 09:36

本文主要是介绍【设计模式】结构型设计模式之 从IO流设计思想来看装饰器模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍

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

装饰器模式代码举例

实现逻辑

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

代码

//装饰器和目标类基础接口
public interface Coffee {String getDescription();double getCost();
}//具体的咖啡,什么都不加
public class SimpleCoffee implements Coffee {@Overridepublic String getDescription() {return "Simple Coffee";}@Overridepublic double getCost() {return 1.0;}
}//装饰器基类,为了避免每个装饰器都要手动重新实现共同父类的接口,即使该装饰器不需要装饰对应方法
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic abstract String getDescription();@Overridepublic double getCost() {return decoratedCoffee.getCost();}
}//摩卡咖啡装饰器,增加风味描述、增加价格
public class MochaDecorator extends CoffeeDecorator {public MochaDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", Mocha";}@Overridepublic double getCost() {return super.getCost() + 0.5;}
}//奶油装饰器,增加奶油、增加价格
public class WhipDecorator extends CoffeeDecorator {public WhipDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", Whip";}@Overridepublic 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,这样既实现了缓存读取又实现类按照基本数据类型来读取。

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

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

这篇关于【设计模式】结构型设计模式之 从IO流设计思想来看装饰器模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1047804

相关文章

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

JavaScript装饰器从基础到实战教程

《JavaScript装饰器从基础到实战教程》装饰器是js中一种声明式语法特性,用于在不修改原始代码的情况下,动态扩展类、方法、属性或参数的行为,本文将从基础概念入手,逐步讲解装饰器的类型、用法、进阶... 目录一、装饰器基础概念1.1 什么是装饰器?1.2 装饰器的语法1.3 装饰器的执行时机二、装饰器的

C++中的解释器模式实例详解

《C++中的解释器模式实例详解》这篇文章总结了C++标准库中的算法分类,还介绍了sort和stable_sort的区别,以及remove和erase的结合使用,结合实例代码给大家介绍的非常详细,感兴趣... 目录1、非修改序列算法1.1 find 和 find_if1.2 count 和 count_if1

Redis中群集三种模式的实现

《Redis中群集三种模式的实现》Redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1. Redis三种模式概述2、Redis 主从复制2.1 主从复制的作用2.2 主从复制流程2

java中的DDD思想指的是什么及在Java中的体现详解

《java中的DDD思想指的是什么及在Java中的体现详解》领域驱动设计(简称DDD)是一种软件开发方法,旨在通过对业务领域的深入理解,构建高内聚、低耦合的系统,:本文主要介绍java中的DDD思... 目录前言什么是 DDD(Domain-Driven Design)?核心思想:DDD 的三大核心概念DD

深入理解MySQL流模式

《深入理解MySQL流模式》MySQL的Binlog流模式是一种实时读取二进制日志的技术,允许下游系统几乎无延迟地获取数据库变更事件,适用于需要极低延迟复制的场景,感兴趣的可以了解一下... 目录核心概念一句话总结1. 背景知识:什么是 Binlog?2. 传统方式 vs. 流模式传统文件方式 (非流式)流

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点