前言

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. [No0000193]Chrome浏览器控制台(console)花式调试

    对前端开发者来说,Chrome Dev Tools(开发者工具,以下简称CDT)是一个不可或缺的开发调试工具,但是你可能只用过console.log(),却不知道console还有很多功能强大的调试方 ...

  2. React中redux表单编辑

    reduxForm中反写数据在输入框中,数据是从别的模块拉取 // 编辑应用表单 class EditCode extends React.Component { constructor(props) ...

  3. [人工智能] 安装python jupyter

    1.  什么是python jupyter ? 简单的说,可以理解为一个IDE. http://jupyter.org/ 2.  安装python jupyter notebook http://ju ...

  4. [daily][python2] int型IP地址与string型IP地址互转

    使用python2,类似如下操作. >>> import socket >>> import struct >>> socket.ntohl(]) ...

  5. Intellij IDEA注册激活破解

    1.2017年适用(2016.3.5到2017.2.4版均生效) 安装IntelliJ IDEA 最新版 启动IntelliJ IDEA 输入 license时,选择输入 [License serve ...

  6. IntelliJ IDEA java文件注释模板

    一.设置 二.注释模板 /*** @version: java version 1.7+* @Author : * @Explain :* @contact: * @Time : ${DATE} ${ ...

  7. java中加与不加public

    加public表示全局类,该类可以import到任何类内.不加public默认为保留类,只能被同一个包内的其他类引用来源:https://blog.csdn.net/qq_15037231/artic ...

  8. demo1:会下蛋的机器人

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 使用go语言数据库

    1.下载并导入数据库驱动包(注意配置环境变量.数据库.go.以及ENV) 这里选择了Go-MySQL-Driver这个实现.地址是:https://github.com/go-sql-driver/m ...

  10. npm -i 与npm install -s与-d的区别

    npm i module_name -S = > npm install module_name --save 写入到 dependencies 对象 npm i module_name -D ...