前言

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整体框架的更多相关文章

  1. 从装饰者模式的理解说JAVA的IO包

    1. 装饰者模式的详解 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性 的替代方案. 装饰者模式设计类之间的关系: 其 中Component是一个超类,ConcreteC ...

  2. 装饰器模式(Decorator)——深入理解与实战应用

    本文为原创博文,转载请注明出处,侵权必究! 1.初识装饰器模式 装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能.其结构图如下: Component为统一接口,也是装饰类和被装 ...

  3. 深入理解java:4.2. 框架编程之Spring框架的设计理念

    什么是Spring呢? Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. Spring优点 简单了解Spring之后,我们看一下Spri ...

  4. 深入理解java:4.3. 框架编程之MyBatis原理深入解析

    1 引言 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架.再而论述Mybatis作为一个数据持久层框架本身有待改进之处. 2 ...

  5. 深入理解java:4.1. 框架编程之Spring MVC

    说到java的mvc框架,struts2和springmvc想必大家都知道, Spring MVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高 ...

  6. 【设计模式】装饰者模式(DecoratorMode0

    From: https://liudongdong1.github.io/ 装饰者模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,增加对象功能来说,装饰模式比生成子类实 ...

  7. 从源码角度理解Java设计模式——装饰者模式

    一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...

  8. Java装饰者模式(Decorator)

    一.定义 装饰模式的设计理念主要是以对客户端透明的方式动态扩展对象的功能,是继承关系的一个替代(继承会产生大量的子类,而且代码有冗余).装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展.装饰 ...

  9. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

随机推荐

  1. 添加一个Activity

    #Android中增加一个Activity 1. 在AndroidManifest.xml中增加: <activity android:name="com.example.NewAct ...

  2. 7.1-uC/OS-III中断管理

    在 uC/OS 系统中,中断相当于一个优先级最高的任务.中断一般用于处理比较紧急的事件, 而且只做简单处理,例如标记该事件,带退出中断后再做详细处理.在使用 uC/OS系统时, 一般建议使用信号量. ...

  3. python获取一年所有的日期

    python获取一年所有的日期 自动识别闰年. import arrow def isLeapYear(years): ''' 通过判断闰年,获取年份years下一年的总天数 :param years ...

  4. SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑

    SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑 关键词:CDC   原文:http://www.cnblogs.com/chenxizhang/arc ...

  5. HTML5 元素属性介绍

    HTMLElement 表示所有的 HTML 元素. 这里将以事件属性和非事件属性的分类进行介绍. 事件属性大多继承自GlobalEventHandlers,非事件属性大多继承自Element. 菜单 ...

  6. 【Spark-core学习之九】 Spark案例

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  7. Bamboo基础概念

    1.project     1)提供报告.展板.连接   |——2.plan       1)指定默认代码仓库(同一个仓库)       2)构建触发条件的配置       3)构建结果的发送与通知 ...

  8. i2c状态机方法设计-verilog

    2010-09-05 21:04:00 verilog语言基础学的差不多了.接着就是看看华为的语言编写规范.状态机设计方法是fpga的重要设计方法.所以我要记上一笔. 只要会FSM方法,用fpga编写 ...

  9. 项目中常用的javascript/jquery操作

    1.判断复选框是否被选中? $("#cpuWindow").is(':checked'); 2.设置复选框被选中: $("#cpuWindow").prop(& ...

  10. pssh批量管理

    因为公司金融项目正式上线,有等保的要求,所有的线上服务器对操作过历史命令都要记录下来,需要修改一部分的配制文件.总共有300多台Linux服务器,总不能一台一台去改吧.首先想到是ansble,salt ...