由装饰者模式来深入理解Java I/O整体框架
前言
Java里面的I/O这一部分看过很多遍,每次看完之后特别混乱,又是输入流,又是输出流,又是字符流,又是字节流,还有什么过滤流,缓冲流。每次看得我如入云里雾里,直到后面看了设计模式这一块,才算真正的对Java I/O这一块有了整体的了解,理解起Java流也就容易许多。这篇博客先介绍装饰者模式,然后结合Java流看看装饰者模式如何应用到Java流中的。
装饰者模式
装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。在如下三种情况下可以选择使用装饰者模式。
- 1)需要扩展一个类的功能,或给一个类增加附加责任。
- 2)需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
- 3)需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得 不现实。
装饰者角色结构如下图所示:

由上图可知在装饰者模式中一共有两个角色,一个是被装饰者,一个是装饰者。装饰者类和被装饰者类有共同的超类。在具体装饰者类上面还有一个抽象装饰者类。抽象装饰者类的主要功能是强制具体装饰者类实现对被装饰者类增加的功能。装饰者的类图如下:

装饰者模式实例
现在有一杯白开水(WaterClass),想向白开水里面加茶叶(TeaClass),加点糖(SugarClass),或者加点盐(SaltClass)。也许会认为那还不简单吗,加茶叶的白开水就再生成一个(WaterWithTeaClass),加糖的白开水就再生成一个(WaterWithSugarClass)这样不就行了吗?但是如果我们既要加糖又要加茶叶,或者加盐加糖这样的组合会很多,可能就要生成很多的类,造成类泛滥。这时候就要用到装饰者模式了。下面看看装饰者模式是如何轻松解决这个问题的。

WaterComponent:(被装饰者)
public class WaterComponent implements DrinkComponent{
@Override
public void operation() {
// TODO Auto-generated method stub
System.out.print("water drink");
}
}
SugarDecorator:(装饰者)
public class SugarDecorator extends DrinkDecorator{
public SugarDecorator(DrinkComponent component) {
super(component);
// TODO Auto-generated constructor stub
}
public void operation()
{
component.operation();
System.out.print(",with sugar");
}
}
TeaDecorator:(装饰者)
public class TeaDecorator extends DrinkDecorator{
public TeaDecorator(DrinkComponent component) {
super(component);
// TODO Auto-generated constructor stub
}
public void operation()
{
component.operation();
System.out.print(",with Tea");
}
}
MainClass
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
WaterComponent water=new WaterComponent();
SugarDecorator sugar=new SugarDecorator(water);
//往白开水里面加糖。
TeaDecorator tea=new TeaDecorator(sugar);
//往加糖的白开水里面加茶叶。
tea.operation();
/*一杯有茶叶和糖的白开水就这样产生了,你也可以自由的往白开水里面加自己喜欢的东西,而并不造成类泛滥只需要继承DrinkDecorator就行*/
}
}
由这个实例应该对装饰者模式有了了解,下面就来看看装饰者模式是如何应用到Java I/O中来的。
装饰者模式与Java I/O
先用一幅图来看看Java I/O到底是什么。下面的这幅图生动的刻画了Java I/O的作用。

由上图可知在Java中应用程序通过输入流(InputStream)的Read方法从源地址处读取字节,然后通过输出流(OutputStream)的Write方法将流写入到目的地址。流的来源主要有三种:
- ①本地的文件(File)
- ②控制台
- ③通过socket实现的网络通信
下面的图可以看出Java中的装饰者类和被装饰者类以及它们之间的关系,这里只列出了InputStream中的关系。

由上图可以看出只要继承了FilterInputStream的类就是装饰者类,可以用于包装其他的流,装饰者类还可以对装饰者和类进行再包装。下面看一下Java中包装流的实例:
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class StreamDemo { public static void main(String[] args) throws IOException{ DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream("D:\\JAVAworkspace\\ProgramTest\\src\\StreamDemo.java")));
while(in.available()!=0)
{
System.out.print((char)in.readByte());
}
in.close();
} }
上面程序中对流进行了两次包装,先用 BufferedInputStream将FileInputStream包装成缓冲流也就是给FileInputStream增加缓冲功能,再DataInputStream进一步包装方便数据处理。
实现自己的包装流
了解了装饰者模式以及在Java中的应用,下面就来实现一个自己的包装流,要实现装饰者类,按照上面的图必须先得实现FilterInputStream装饰者抽象类。来实现这样一个操作的装饰者类:将输入流中的所有小写字母变成大写字母。
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream; public class UpperCaseInputStream extends FilterInputStream { protected UpperCaseInputStream(InputStream in) {
super(in);
} @Override
public int read() throws IOException {
int c=super.read(); return (c==-1?c:Character.toUpperCase(c));
} @Override
public int read(byte[] b, int off, int len) throws IOException {
int result=super.read(b, off, len);
for(int i=off;i<off+result;i++)
{
b[i]=(byte)Character.toUpperCase((char)b[i]);
}
return result;
} public static void main(String[] args) throws IOException {
int c;
InputStream in=new UpperCaseInputStream(new FileInputStream("D:\\JAVAworkspace\\ProgramTest\\src\\StreamDemo.java"));
try {
while((c=in.read())>=0)
{
System.out.print((char)c);
}
}
finally{
in.close();
}
} }
输出结果:
IMPORT JAVA.IO.BUFFEREDINPUTSTREAM;
IMPORT JAVA.IO.DATAINPUTSTREAM;
IMPORT JAVA.IO.FILEINPUTSTREAM;
IMPORT JAVA.IO.IOEXCEPTION;
PUBLIC CLASS STREAMDEMO { PUBLIC STATIC VOID MAIN(STRING[] ARGS) THROWS IOEXCEPTION{
DATAINPUTSTREAM IN=NEW DATAINPUTSTREAM(NEW BUFFEREDINPUTSTREAM(NEW FILEINPUTSTREAM("D:\\JAVAWORKSPACE\\PROGRAMTEST\\SRC\\STREAMDEMO.JAVA")));
WHILE(IN.AVAILABLE()!=0)
{
SYSTEM.OUT.PRINT((CHAR)IN.READBYTE());
}
IN.CLOSE();
} }
参考文献
1.java编程思想(Thinking In Java)
2.Head First 设计模式
3.https://www.javatpoint.com/java-io
原文:https://blog.csdn.net/u013309870/article/details/75735676
由装饰者模式来深入理解Java I/O整体框架的更多相关文章
- 从装饰者模式的理解说JAVA的IO包
1. 装饰者模式的详解 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性 的替代方案. 装饰者模式设计类之间的关系: 其 中Component是一个超类,ConcreteC ...
- 装饰器模式(Decorator)——深入理解与实战应用
本文为原创博文,转载请注明出处,侵权必究! 1.初识装饰器模式 装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能.其结构图如下: Component为统一接口,也是装饰类和被装 ...
- 深入理解java:4.2. 框架编程之Spring框架的设计理念
什么是Spring呢? Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. Spring优点 简单了解Spring之后,我们看一下Spri ...
- 深入理解java:4.3. 框架编程之MyBatis原理深入解析
1 引言 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架.再而论述Mybatis作为一个数据持久层框架本身有待改进之处. 2 ...
- 深入理解java:4.1. 框架编程之Spring MVC
说到java的mvc框架,struts2和springmvc想必大家都知道, Spring MVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高 ...
- 【设计模式】装饰者模式(DecoratorMode0
From: https://liudongdong1.github.io/ 装饰者模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,增加对象功能来说,装饰模式比生成子类实 ...
- 从源码角度理解Java设计模式——装饰者模式
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
- Java装饰者模式(Decorator)
一.定义 装饰模式的设计理念主要是以对客户端透明的方式动态扩展对象的功能,是继承关系的一个替代(继承会产生大量的子类,而且代码有冗余).装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展.装饰 ...
- (十)装饰器模式详解(与IO不解的情缘)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...
随机推荐
- linux--- python3环境部署篇
环境部署 我们在pycharm上都是自己设置的python3解释器的环境变量,使得代码能够正常执行!可是怎么能让我们的python代码在LINUX上跑起来呢? linux是内置python,可是内置的 ...
- Gym 101194D / UVALive 7900 - Ice Cream Tower - [二分+贪心][2016 EC-Final Problem D]
题目链接: http://codeforces.com/gym/101194/attachments https://icpcarchive.ecs.baylor.edu/index.php?opti ...
- 删除64位ODBC数据源DNS
1.按照打开管理工具-打开数据源(ODBC),进入如下界面,选择用户DSN删除,发现报错一直删除不了. 2.成功删除:进入如下图路径,打开ODBC数据源管理工具,选择要删除的DSN就可以成功删除啦.
- 6、Flutter Error waiting for a debug connection: ProcessException: adb did not report f(转)
1.错误信息 Error waiting for a debug connection: ProcessException: adb did not report forwarded port 2.解 ...
- 家庭记账本之微信小程序(八)
寒假总结 寒假充满着腥风血雨,不过在努力下还是完成了寒假的任务,虽说没有出去找活干,毕竟在寒假这段时间不怎么好找,但是我在自己家的店里帮这父母工作了一段时间,也算是颇有收获,在短暂的学习后也算勉强完成 ...
- 网络请求(I)
NSURLSession 代理方法 有的时候,我们可能需要监听网络请求的过程(如下载文件需监听文件下载进度),那么就需要用到代理方法. #import "ViewController.h&q ...
- Poj1979 Red and Black (DFS)
Red and Black Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 47466 Accepted: 25523 D ...
- week_one-python基础 基本语法、流程控制
金角大王的紫金葫芦,python开发环境介绍链接:http://list.youku.com/albumlist/show/id_28961509.html # Author:larlly pytho ...
- 爬虫----selenium模块
一.介绍 selenium最初是一个测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳 ...
- 20190402 管道符,分号,单引号,双引号,&&的使用
:分号叫顺序执行 格式:命令:命令 && :前一条命令执行成功,后面命令继续执行:前面命令执行失败,后者不执行 格式:命令+空格&&空格+命令 || :两管道逻辑执行, ...