java-IO流(5)-IO流中的设计模式(装饰器模式和适配器模式)的介绍

2023-11-20

目录

1装饰器模式

1.1定义

1.2代码实现

1.3装饰器特点

1.4装饰器在IO流中的使用

2配适器模式

2.1Adapter适配器

2.2代码实例

2.3适配器特点

2.4适配器优缺点

2.5适配器在IO中的使用

3装饰器与适配器异同点


1装饰器模式

1.1定义

装饰模式是在不改变原类文件和不使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

注意:

  • 不改变原类文件
  • 不使用继承
  • 动态扩展

图片 1.png

Component:

为统一接口,也是装饰类和被装饰类的基本类型。

ConcreteComponent:

为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。

Decorator:

是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。

ConcreteDecorator:

是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。

1.2代码实现

/**
 * 是装饰类和被装饰类的基础,统一的接口 Component
 */
public interface Component {
    public void method();
}

/**
 * 被装饰类 是Component接口的具体实现
 */
public class ConctreteComponent implements Component {
    @Override
    public void method() {
        System.out.println("ConctreteComponent ...");
    }
}


/**
 * 装饰类Decorator 
 * 实现了Component接口
 */
public abstract class Decorator implements Component {

    //内存维护了一个Component实例
    private Component component;

    //通过构造函数来实例化内存的component属性
    public Decorator(Component component) {
       this.component = component;
    }

    @Override
    public void method() {
        component.method();
    }
}

/**
 * 具体的装饰类A  ConcreteDecoratorA 
 */
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    public void methodA() {
        System.out.println("装饰器A提供的新的功能");
    }

    @Override
    public void method() {
        System.out.println("针对该方法添加一层包装");
        super.method();
        System.out.println("A包装结束");
    }
}

测试代码

//创建被装饰类的实例
        Component component = new ConctreteComponent();
        component.method(); //原来的实现
        System.out.println("------------------");

//装饰成新的类
        ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);
        concreteDecoratorA.method(); //原有的方法
        concreteDecoratorA.methodA(); //装饰成A类后新提供的方法

1.3装饰器特点

它必须持有一个被装饰的对象(作为成员变量)。

它必须拥有与被装饰对象相同的接口(多态调用、扩展需要)。

它可以给被装饰对象添加额外的功能。

总结:保持接口,动态增强性能。

1.4装饰器在IO流中的使用

/**
         * inputstream相当于统一的接口,给被装饰类和装饰类的基本的类型
         * FileInputStream相当于原始的被封装的对象,为具体的实现类,他对inputstream方法有完整的实现
         */
        FileInputStream inputStream = new FileInputStream(path);


        /**
         * FilterInputStream是装饰类,其继承自InputStream基类
         * 内部存在一个InputStream实例,需要通过构造函数来实例化内部属性
         * 
         * BufferInputStream就是具体的装饰类
         * 
         */
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

InputStream是被装饰类和装饰类的基本类型,这里是通过抽象类的形式提供的,相当于Component接口

FileInputStream是具体的被装饰类,是继承自InputStream,提供了完备的InputStream方法的实现。相当于是concreateComponent类

FilterInputStream是装饰器类,其继承InpuStream,内部维护了一个Inpustream实现类,相当于Decorator类

BufferInputstream是具体的装饰器类,继承自FilterInputStream装饰器类,提供了具有特有的缓冲功能的特点

图片 1.png

在类图上标注了各个类负责的角色,并且使用背景颜色将InputStream和Reader体系分开,其中左半部分就是InputStream的装饰体系,右半部分就是Reader的装饰体系,并且他们之间的桥梁是InputStreamReader,他们每一个装饰体系都与上面标准的装饰器模式类图极其相似

总之:装饰器模式就是一个可以非常灵活的动态扩展类功能的设计模式,它采用组合的方式取代继承,使得各个功能的扩展更加独立和灵活。

2配适器模式

2.1Adapter适配器

适配器定义:将一个类的接口转换成客户希望的另外一个接口,Adapter模式使原本由于接口不兼容而不能一起工作的那些类可以一起工作

适配器模式分两种:类适配器和对象适配器

  • 使用继承(就是所谓的类适配器模式)
  • 使用组合(所谓的对象适配器模式)

屏幕快照 2020-02-28 下午6.53.18.png

适配器所涉及的角色有:

Target(目标接口):所要转换的所期待的接口

Adaptee(源角色):需要适配的类

Adapter(适配器):将源角色适配成目标接口,一般持有源接口的引用(或者继承源接口),且实现目标接口。

Client(客户类):通过目标角色获取服务

2.2代码实例

手机充电器适配:

存在一个Typec接口的充电器,期望提供一个USB接口的充电器

/**
 * 源角色,需要适配的类
 */
public class TypeC {
    public void typec(){
        System.out.println("TypeC 充电器实现");
    }
}


/**
 * 目标角色
 * 用户期望使用use充电器
 */
public interface USB {
    public void use();
}


/**
 * 适配器类
 * 将源角色适配成目标角色
 */
public class Adapter extends TypeC implements USB {

    @Override
    public void use() {
        super.typec();
    }
}

使用:

  //客户需要的是use接口
        USB usb = new Adapter();
        usb.use();

2.3适配器特点

1、适配器对象实现原有接口

2、适配器对象组合一个实现新接口的对象(这个对象也可以不实现一个接口,只是一个单纯的对象)

3、对适配器原有接口方法的调用被委托给新接口的实例的特定方法(重写旧接口方法来调用新接口功能。)

2.4适配器优缺点

  • 优点

有更好的复用性。系统需要使用现有的类,但此类接口不符合系统需要,通过适配器模式让这些功能得到很好的复用

有更好的扩展性。实现适配器,可以调用自己开发的功能

  • 缺点

过多使用适配器会使得系统非常凌乱,明明调用的是A接口,内部却被适配成了B接口。因此除非必要,不推荐使用适配器,而是直接对系统重构

适用场景

软件系统结构需要升级或扩展,又不想影响原有系统稳定运行的时候

转换类之间的差別不是很大的时候

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

2.5适配器在IO中的使用

在IO中适配器的使用也比较广泛

适配器角色就是InputStreamReader,

被适配的角色是InputStream类的实例对象,

目标接口是Reader类。

可以看到,InputStreamReader实现了Reader接口,并且持有了InputStream的引用,这里是通过StreamDecoder类间接持有的,因为从byte到char 要经过编码。

/******************Reader类(目标类)******************/
public abstract class Reader implements Readable, Closeable {
abstract public int read(char cbuf[], int off, int len) throws IOException;
abstract public void close() throws IOException;
}
/******************InputStreamReader类(适配器类)******************/
public class InputStreamReader extends Reader {
    private final Str·r sd;
    //持有对被适配对象的引用
    public InputStreamReader(InputStream in) {
        super(in);
        try {
            //通过StreamDecoder类间接引用被适配的对象
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null);
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }
    //…(省略的代码)
 }
 /******************InputStream类(被适配类)******************/
 public abstract class InputStream implements Closeable {
 //代码省略
}

u=3278792405,2157414221&fm=26&gp=0.png

3装饰器与适配器异同点

装饰器与适配器都有一个别名叫做 包装模式(Wrapper),它们看似都是起到包装一个类或对象的作用,但是使用它们的目的很不一一样。

适配器模式:是要将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的。

装饰器模式:不是要改变被装饰对象的接口,而是恰恰要保持原有的接口,但是增强原有对象的功能,或者改变原有对象的处理方式而提升性能。所以这两个模式设计的目的是不同的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java-IO流(5)-IO流中的设计模式(装饰器模式和适配器模式)的介绍 的相关文章

  • 在java中轮询Http服务器(重复发送http get请求)

    当对其进行 REST 调用时 我的 Web 服务器会发送一些信息 我想不断轮询该服务器 间隔5秒后重复发送HTTP GET请求 以检查返回的信息是否有任何变化 做到这一点最有效的方法是什么 您能提供一些代码示例吗 请注意 我只想开发客户端代
  • Java:扩展类并实现具有相同方法的接口

    可能无法完成以下操作 我收到编译错误 继承的方法 A doSomthing int 无法隐藏 B 中的公共抽象方法 public class A int doSomthing int x return x public interface
  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • Android:文本淡入和淡出

    我已阅读此 stackoverflow 问题和答案 并尝试实现文本淡入和淡出 Android中如何让文字淡入淡出 https stackoverflow com questions 8627211 how to make text fade
  • Jframe 内有 2 个 Jdialogs 的 setModal 问题

    当我设置第一个选项时 我遇到了问题JDialog模态 第二个非模态 这是我正在尝试实现的功能 单击 测试对话框 按钮 一个JDialog有名字自定义对话框 主要的将会打开 如果单击 是 选项自定义对话框主 其他JDialog named 自
  • 从 MATLAB 调用 Java?

    我想要Matlab程序调用java文件 最好有一个例子 需要考虑三种情况 Java 内置库 也就是说 任何描述的here http docs oracle com javase 6 docs api 这些项目可以直接调用 例如 map ja
  • 将巨大的模式编译成Java

    有两个主要工具提供了将 XSD 模式编译为 Java 的方法 xmlbeans 和 JAXB 问题是 XSD 模式确实很大 30MB 的 XML 文件 大部分模式在我的项目中没有使用 所以我可以注释掉大部分代码 但这不是一个好的解决方案 目
  • 提供节点名或服务名,或未知 Java

    最近我尝试运行我的 Java 项目 每当我运行它并将其打开到我得到的服务器地址时 Unable to determine host name java net UnknownHostException Caused by java net
  • 如何在字段值无效的情况下更改 Struts2 验证错误消息?

    我在 Web 表单上使用 Struts2 验证 如果字段假设为整数或日期 则
  • Java Applet 中的 Apache FOP - 未找到数据的 ImagePreloader

    我正在研究成熟商业产品中的一个问题 简而言之 我们使用 Apache POI 库的一部分来读取 Word DOC 或 DOCX 文件 并将其转换为 XSL FO 以便我们可以进行标记替换 然后 我们使用嵌入到 Java 程序中的 FOP 将
  • Java继承,扩展类如何影响实际类

    我正在查看 Sun 认证学习指南 其中有一段描述了最终修饰符 它说 如果程序员可以自由地扩展我们所知的 String 类文明 它可能会崩溃 他什么意思 如果可以扩展 String 类 我是否不会有一个名为 MyString 的类继承所有 S
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • Java Swing - 如何禁用 JPanel?

    我有一些JComponents on a JPanel我想在按下 开始 按钮时禁用所有这些组件 目前 我通过以下方式显式禁用所有组件 component1 setEnabled false 但是有什么办法可以一次性禁用所有组件吗 我尝试禁用
  • Android S8+ 警告消息“不支持当前的显示尺寸设置,可能会出现意外行为”

    我在 Samsung S8 Android 7 中收到此警告消息 APP NAME 不支持当前的显示尺寸设置 可能会 行为出乎意料 它意味着什么以及如何删除它 谢谢 通过添加解决supports screens 机器人 xlargeScre
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何
  • 子类构造函数(JAVA)中的重写函数[重复]

    这个问题在这里已经有答案了 为什么在派生类构造函数中调用超类构造函数时 id 0 当创建子对象时 什么时候在堆中为该对象分配内存 在基类构造函数运行之后还是之前 class Parent int id 10 Parent meth void
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • 抛出 Java 异常时是否会生成堆栈跟踪?

    这是假设我们不调用 printstacktrace 方法 只是抛出和捕获 我们正在考虑这样做是为了解决一些性能瓶颈 不 堆栈跟踪是在构造异常对象时生成的 而不是在抛出异常对象时生成的 Throwable 构造函数调用 fillInStack
  • Java 11 - 将 Spring @PostConstruct 替换为 afterPropertiesSet 或使用 initMethod

    我正在使用 spring 应用程序 有时会使用 PostConstruct用于代码和测试中的设置 看来注释将被排除在外Java 11 https www baeldung com spring postconstruct predestro
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp

随机推荐