Java 入门指南:Java IO 设计模式

Java 设计模式是一组被广泛应用于Java程序设计中的解决常见问题的可复用设计方案。这些设计模式通过提供一套经过验证的面向对象的设计原则和思想,可以帮助开发人员更好地组织和设计他们的代码。

在Java IO 中,并没有像创建型、结构型和行为型等常见的设计模式那样有明确的命名模式。然而,Java IO库本身包含了一些常见的设计概念和模式,可以用来引导开发人员设计高效可靠的 IO 代码。

流式模式

Java IO库中的核心概念是流(Stream),它允许以连续的、有序的方式读取或写入数据。流的使用可以有效地处理各种不同类型的数据(如字节、字符或对象),并将其串联在一起形成处理管道

IO流式模式(IO Streaming Pattern) 是一种基于流式处理的IO操作模式,用于实现对数据流进行逐个处理的输入输出操作。它提供了一种便捷且高效的方式来读取和写入大量的数据,适用于处理文件、网络通信等场景。

在IO流式模式中,数据以连续的、逐个的方式流动,而不是一次性读取或写入整个数据。这样可以减少对系统资源的占用,并允许实时地处理数据,而不需要等待所有数据就绪。

在Java中,可以通过使用 InputStreamOutputStream 类及其具体子类来实现IO流式模式。例如,可以使用 BufferedInputStream 和BufferedOutputStream类 来处理字节流;使用 BufferedReaderBufferedWriter 类 来处理字符流。这些类提供了缓冲区的支持,可以提高IO操作的性能。

在IO流式模式中,读取数据时,可以通过循环逐个读取数据,并对每个读取的数据做相应的处理。写入数据时,可以将数据分成适当大小的块,逐块写入到目标位置。

流式模式的优点包括:

  1. 节省内存:不需要一次性加载或写入整个数据,而是逐个处理,节省了内存的使用。

  2. 实时处理:可以实时地处理数据流,不需要等待所有数据就绪。

  3. 支持大数据量:可以处理大量的数据,适用于处理大型文件、网络通信等场景。

需要注意的是,在使用IO流式模式时,要注意流的关闭以及正确的异常处理,以确保资源的正确释放和程序的健壮性。

缓冲模式

缓冲模式(Buffering Pattern) 是一种常见的设计模式,用于提高IO操作的效率和性能。它通过引入缓冲区来减少对底层资源(如文件、网络)的频繁访问,从而减少实际的IO操作次数。

在Java中,缓冲模式可以用于不同类型的IO流,如字节流(BufferedInputStreamBufferedOutputStream)和字符流(BufferedReaderBufferedWriter)。这些缓冲流类实现了缓冲模式,可以提供更高效的IO操作。

当应用程序需要进行大量的IO操作时,直接每次访问底层资源可能会导致性能下降。而通过使用缓冲区,可以将多个IO操作捆绑在一起,一次性操作更大的数据块,从而减少了真实的IO次数。这样可以有效地减少IO的开销,提高程序的性能。

缓冲模式的基本原理是,在实际IO操作之前,首先将数据暂存到缓冲区中。然后,当缓冲区满了或者达到一定条件时(如调用flush()方法),将缓冲区中的数据一次性写入到底层的资源中。同样,在读取数据时,也是先将一定数量的数据从底层资源读取到缓冲区,并在之后逐个从缓冲区中读取。

使用缓冲模式可以大大减少对底层资源的访问次数,从而提高IO操作的效率。尤其在读写频繁的场景下,缓冲模式非常有效。但需要注意的是,为了确保数据的完整性和及时性,使用缓冲模式时要记得在适当的时候进行刷新(flush)或关闭(close)操作,以确保缓冲区中的数据被正确地写入或清空。

装饰器模式

装饰器(Decorator)模式 可以在不改变原有对象的情况下拓展其功能。

装饰器模式通过组合替代继承来扩展原始类的功能,通过在原有的输入输出流上添加装饰器对象,来动态地给输入输出流增加额外的功能,在一些继承关系比较复杂的场景(IO 这一场景各种类的继承关系就比较复杂)更加实用

在IO装饰器模式中,定义了一个抽象的装饰器类,该类实现了与原始输入输出流相同的接口,并且包含一个原始输入输出流的引用。装饰器类可以通过对原始输入输出流进行包装,来增加新的功能或行为。

通过使用IO装饰器模式,可以实现以下效果:

  1. 动态扩展功能:可以根据需要添加不同的装饰器对象,来增强输入输出流的功能,无需修改原始输入输出流的代码。

  2. 层次化的装饰:可以通过组合多个装饰器对象,实现对输入输出流功能的叠加,形成层次化的装饰效果。

  3. 无侵入式修改:使用装饰器模式可以在不修改原始输入输出流的情况下,对其进行功能增强,保持代码的稳定性和可维护性。

使用IO装饰器模式的关键点在于:

  1. 定义一个抽象装饰器类,该类实现与原始输入输出流相同的接口,并包含一个原始输入输出流的引用。

  2. 创建具体的装饰器类,继承抽象装饰器类,并通过调用原始输入输出流的方法来包装原始输入输出流,实现额外的功能。

  3. 在客户端代码中,根据需要选择合适的装饰器对象,并通过层层包装来实现功能增强。

适配器模式

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适配器模式的主要用途有:

  • 需要复用一些现存的类,但是这些类的接口不符合要求时。

  • 需要创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口不兼容的类)协同工作。

  • 需要使用已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以用单个类来适配多个适配者类。

我们将适配器模式应用于IO,首先定义一个旧系统的IO接口:

java">public interface LegacyIO {void read(String path);void write(String path, String content);
}

然后定义一个新的数据格式处理类,比如 XML,但它并不符合旧系统的接口:

java">public class XmlIO {public void load(String path) {System.out.println("Loading XML from " + path);}public void save(String path, String content) {System.out.println("Saving XML to " + path);}
}

接下来创建一个适配器类,它实现了旧系统的接口,并将调用转发给新的XML IO类:

java">public class XmlIOAdapter implements LegacyIO {private XmlIO xmlIO;public XmlIOAdapter() {this.xmlIO = new XmlIO();}@Overridepublic void read(String path) {xmlIO.load(path);}@Overridepublic void write(String path, String content) {xmlIO.save(path, content);}
}

最后,在客户端代码中,可以像使用旧系统的IO一样使用新的适配器:

java">public class Client {public static void main(String[] args) {LegacyIO io = new XmlIOAdapter();io.read("/path/to/file.xml");io.write("/path/to/file.xml", "<xml><content>Some data</content></xml>");}
}

工厂模式

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。工厂模式可以用来创建一系列相关或依赖对象,而无需指定它们具体的类。

工厂模式的主要用途有:

  • 当一个类不知道它所必须创建的对象的类的时候。

  • 当一个类希望由它的子类来指定它所创建的对象的时候。

  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且希望让使用者统一接口的时候。

如果我们想要根据不同的需求动态地选择不同的IO处理类(例如,根据文件扩展名决定使用哪种IO处理器),那么工厂模式就非常适合这种情况。工厂模式可以帮助我们在运行时根据条件选择合适的IO处理类。

我们将工厂模式应用于IO,首先定义一个抽象的IO处理器接口:

java">public interface IOProcessor {void process(String path);
}

然后定义具体的IO处理器实现:

java">public class TextIOProcessor implements IOProcessor {@Overridepublic void process(String path) {System.out.println("Processing text file at " + path);}
}public class ImageIOProcessor implements IOProcessor {@Overridepublic void process(String path) {System.out.println("Processing image file at " + path);}
}

接着定义一个工厂类来创建具体的IO处理器:

java">public class IOProcessorFactory {public static IOProcessor getProcessor(String extension) {if ("txt".equalsIgnoreCase(extension)) {return new TextIOProcessor();} else if ("jpg".equalsIgnoreCase(extension) || "png".equalsIgnoreCase(extension)) {return new ImageIOProcessor();}throw new IllegalArgumentException("Unsupported file type.");}
}

最后,在客户端代码中,可以根据文件扩展名来获取相应的处理器:

java">public class Client {public static void main(String[] args) {String filePath = "/path/to/file.txt";String extension = filePath.substring(filePath.lastIndexOf('.') + 1);IOProcessor processor = IOProcessorFactory.getProcessor(extension);processor.process(filePath);}
}

通过这样的设计,客户端代码不需要关心具体使用了哪种IO处理器,而是通过工厂类根据文件类型动态地获取相应的处理器实例。这种方式不仅简化了客户端代码,也使得系统更加灵活,易于扩展。

策略模式

策略模式(Strategy Pattern) 是一种行为型设计模式,它允许在运行时选择算法的行为。策略模式将算法封装成独立的对象,并使其可以互相替换,从而使算法的变化独立于使用算法的客户端。

在策略模式中,有三个核心角色:

  1. 环境(Context):持有一个策略对象的引用,并在需要时调用策略对象的方法。
  2. 策略(Strategy):定义了算法的接口,具体的算法实现由具体策略类来完成。
  3. 具体策略(Concrete Strategy):实现策略接口,完成具体的算法实现。

IO策略模式(IO Strategy Pattern) 是一种基于策略模式的设计模式,用于实现不同的输入输出策略。它将不同的输入输出操作封装成独立的策略类,并允许在运行时动态选择和切换不同的策略。

在 IO 策略模式中,定义了一个抽象的策略接口或抽象类,描述了输入输出的公共方法。然后,通过创建具体的策略类来实现不同的输入输出策略,例如文件读写、网络通信等。客户端代码可以根据需要选择合适的策略来执行具体的输入输出操作。

IO策略模式的核心思想是将输入输出的逻辑与具体的实现分离,使得可以灵活地选择和切换不同的输入输出策略。这样可以提高代码的可扩展性和复用性,而不需要对现有代码进行修改。

使用IO策略模式的好处包括:

  1. 可扩展性:可以轻松地添加新的输入输出策略,而无需修改现有代码。
  2. 灵活性:可以在运行时动态选择合适的输入输出策略,根据具体需求进行切换。
  3. 可测试性:对于每个具体的输入输出策略,可以单独进行测试,提高代码的可测试性。

在Java中,可以使用策略模式和工厂模式结合来实现IO策略模式。即定义一个策略接口或抽象类来描述输入输出的公共方法,然后创建具体的策略类实现不同的输入输出策略。最后,通过一个工厂类来创建适当的策略对象,并在客户端代码中使用。

观察者模式

观察者模式是一种行为设计模式,它允许定义一个订阅机制,可以用于在对象状态改变时通知多个“观察者”对象,而无需使对象之间紧密耦合。

在观察者模式中,有两个主要角色:

  1. Subject(主题):也称为发布者或被观察者。它是状态持有者,当它的状态发生变化时,会通知所有注册过的观察者。

  2. Observer(观察者):也称为订阅者。它们依赖于主题的状态,并在主题状态发生变化时收到通知,从而做出相应的更新。

在实际的 Java IO 应用中,观察者模式可以用于以下场景:

  • 文件监控:监控文件系统的变更,并通知相关的组件进行处理。
  • 日志记录:当文件操作完成时,通知日志记录器记录日志。
  • 事件驱动架构:基于事件的系统中,当特定的 IO 事件发生时,通知订阅该事件的组件进行处理。

在 Java IO 的上下文中,我们可以设想一个场景,其中有一个 IO 操作(例如文件读写),当操作完成时,需要通知多个不同的组件进行后续处理。这种情况下,我们可以模拟一个基于观察者模式的设计。

下面是一个简化的示例,展示如何在 Java IO 操作中使用观察者模式。

  1. 定义主题接口
java">import java.util.ArrayList;
import java.util.List;public interface IObservable {void addObserver(IObserver observer);void removeObserver(IObserver observer);void notifyObservers();
}public interface IObserver {void update();
}
  1. 实现主题
java">import java.util.ArrayList;
import java.util.List;public class FileOperation implements IObservable {private List<IObserver> observers = new ArrayList<>();public void addObserver(IObserver observer) {observers.add(observer);}public void removeObserver(IObserver observer) {observers.remove(observer);}public void notifyObservers() {for (IObserver observer : observers) {observer.update();}}public void performOperation() {// 模拟文件操作System.out.println("Performing file operation...");// 操作完成后通知观察者notifyObservers();}
}
  1. 实现观察者
java">public class FileOperationLogger implements IObserver {@Overridepublic void update() {System.out.println("File operation completed. Logging the event.");}
}public class FileOperationNotifier implements IObserver {@Overridepublic void update() {System.out.println("File operation completed. Sending notification.");}
}
  1. 主程序
java">public class Main {public static void main(String[] args) {FileOperation fileOperation = new FileOperation();// 注册观察者fileOperation.addObserver(new FileOperationLogger());fileOperation.addObserver(new FileOperationNotifier());// 执行文件操作fileOperation.performOperation();}
}

示例说明

  • 定义接口:首先定义了 IObservableIObserver 接口,分别代表主题和观察者。
  • 实现主题FileOperation 类实现了 IObservable 接口,并维护了一个观察者列表。当文件操作完成时,它会调用 notifyObservers() 方法来通知所有的观察者。
  • 实现观察者FileOperationLoggerFileOperationNotifier 类实现了 IObserver 接口,并在 update() 方法中定义了各自的行为。
  • 主程序:在主程序中,创建了一个 FileOperation 实例,并注册了两个观察者。当执行文件操作后,通过调用 performOperation() 方法触发了观察者的更新。

通过这样的设计,可以使系统更加灵活,易于扩展和维护。观察者模式有助于降低组件间的耦合度,使得各个组件能够独立地工作,并且可以在不修改现有代码的情况下添加新的功能。


http://www.ppmy.cn/embedded/102418.html

相关文章

Linux信号段错误的处理

二、信号捕获 typedef void (*sighandler_t)(int); 功能&#xff1a;说明信号处理函数的格式 sighandler_t signal(int signum, sighandler_t handler); 功能&#xff1a;向内核注册一个信号处理函数 signum&#xff1a;信号编号 handler&#xff1a;函数指针也可使用以下参数…

SSRF漏洞(一)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 1&#xff0c;什么是ssrf。 SSRF漏洞&#xff0c;全称Server-Side Request Forgery&#xff08;服务器端请求伪造&#xff09;&#xff0c;是一种安全漏洞。它允许攻击者构造请求&a…

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题 本文中使用的Jenkins版本为Version 2.452.3 先罗列一下前置问题&#xff1a;Jenkins任务构建完成自动杀掉衍生进程 用过Jenkins的都知道&#xff0c;Jenkins任务构建完成后&#xff0c;是会自动杀掉衍生进程&#xff0c;这…

C语言 | Leetcode C语言题解之第382题链表随机节点

题目&#xff1a; 题解&#xff1a; typedef struct {struct ListNode * head; } Solution;Solution* solutionCreate(struct ListNode* head) {Solution * obj (Solution *)malloc(sizeof(Solution));assert(obj ! NULL);obj->head head;return obj; }int solutionGetRa…

【ceph学习】rados bench性能测试工具介绍

rados bench性能测试工具介绍 radosbench介绍 Ceph 包含 rados bench 命令&#xff0c;用于在 RADOS 存储群集上执行性能基准测试。命令将执行写入测试&#xff0c;以及两种类型的读测试。在测试读取和写入性能时&#xff0c;–no-cleanup 选项非常重要。默认情况下&#xff0c…

插入排序:直接插入排序、希尔排序详细说明

插入排序 基本思想&#xff1a;直接插入排序是⼀种简单的插入排序法&#xff0c;其基本思想是&#xff1a;把待排序的记录按其关键码值的大小逐个插入到⼀个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到⼀个新的有序序列。 在玩扑克牌整理手中…

Day50 | 108.冗余连接 109.冗余连接II

108.冗余连接 108. 冗余连接 题目 题目描述 树可以看成是一个图&#xff08;拥有 n 个节点和 n - 1 条边的连通无环无向图&#xff09;。 现给定一个拥有 n 个节点&#xff08;节点标号是从 1 到 n&#xff09;和 n 条边的连通无向图&#xff0c;请找出一条可以删除的边&…

模型 福格行为

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。BMAP 1 福格行为的应用 1.1 基于福格行为模型的儿童教育应用设计 随着移动互联网的普及&#xff0c;儿童教育应用迅速发展&#xff0c;如何设计出既吸引儿童又能积极促进学习的教育应用成为设计者关…

思维+二分,CF 1019B - The hat

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1019B - The hat 二、解题报告 1、思路分析 一个很关键的信息就是 相邻两…

32 - III. 从上到下打印二叉树 III

comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9832%20-%20III.%20%E4%BB%8E%E4%B8%8A%E5%88%B0%E4%B8%8B%E6%89%93%E5%8D%B0%E4%BA%8C%E5%8F%89%E6%A0%91%20III/README.md 面试题 32 - III. 从上到下…

Oracle发邮件时SMTP服务器配置方法与步骤?

Oracle发邮件功能如何配置&#xff1f;如何优化Oracle发信性能&#xff1f; 为了实现自动化报告和通知&#xff0c;Oracle发邮件功能变得尤为重要。通过配置SMTP服务器&#xff0c;Oracle可以轻松地发送电子邮件。AokSend将详细介绍如何配置Oracle发邮件时的SMTP服务器&#x…

spring mvc面试笔记

简述 SpringMVC 工作原理 ? SpringMVC 工作原理&#xff1a; 1&#xff1a;用户发送请求至前端控制器DispatcherServlet。 2&#xff1a;DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3&#xff1a;处理器映射器找到具体的处理器(可以根据xml配置、注解进行查…

JavaWeb基础 -- SpringMVC请求和响应

JavaWeb基础 – SpringMVC请求和响应 1.SpringMVC响应 1.1 数据响应 1.1.1 响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 1.2 页面跳转 1.2.1 返回字符串形式 直接返回字符串&#xff1a;此种方式会将返回的字符串…

graphRAG原理解析——基于微软graphRAG+Neo4j llm-graph-builder

知识图谱生成 llm-graph-builder&#xff08;以下简称 LGB&#xff09;也使用了最新的 graph RAG 的思路&#xff0c;使用知识图谱来加持RAG&#xff0c;提供更加准确和丰富的知识问答。知识图谱的生成上&#xff0c;利用大模型的泛化能力来自动生成和构建知识图谱&#xff0…

分布式数据一致性小结

文章目录 简介一、线性一致性二、顺序一致性三、因果一致性四、以客户端为中心的一致性参考 简介 分布式一致性问题包括数据一致性问题和事务一致性问题。在此仅关注数据一致性问题&#xff0c;数据一致性问题是因为分布式系统下数据需要复制而导致的。 而数据一致性模型就是…

oracle日常训练

打印表种所有数据 select * from T_GIRL; 创建一个表 create table 表名 (字段名1 数据类型 null,字段名2 数据类型 not null,......,字段名n 数据类型 null );create table T_GIRL (id char(4) not null, -- 编号name varchar2(30) not null, --…

Apache PDFBox

文章目录 一、关于 Apache PDFBox二进制下载构建贡献支持已知限制和问题许可证&#xff08;另见[LICENSE. txt](https://github.com/apache/pdfbox/blob/trunk/LICENSE.txt)&#xff09;出口管制 二、依赖1、核心组件最低要求字体处理XMP元数据使用Maven包含依赖项 2、可选组件…

Python计算机视觉 第4章-照相机模型与增强现实

Python计算机视觉 第4章-照相机模型与增强现实 4.1 针孔照相机模型 针孔照相机模型&#xff08;有时称为射影照相机模型&#xff09;是计算机视觉中广泛使用的照相机模型。对于大多数应用来说&#xff0c;针孔照相机模型简单&#xff0c;并且具有足够的精确度。这个名字来源…

进程终止 等待 替换

文章目录 一.进程的终止进程终止实在做什么&#xff1f;进程终止的3种情况自定义退出码 如何终止进程&#xff1f; 二.进程等待为什么要进行进程等待&#xff1f;进程如何等待&#xff1f;waitwaitpid 阻塞等待 && 非阻塞等待 三.进程的程序替换先看代码 && 现…

Vue3 pinia

1.简介 集中式状态&#xff08;数据&#xff09;管理 和vueX一样 2.安装pinia npm i pinia //引入 createApp用于创建应用 import {createApp} from vue; //引入 App 根组件 import App from ./App.vue;//引入pinia import {createPinia} from pinia;//创建一个应用 const…