博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式(5)------结构型模式-----装饰者设计模式(IO流的应用)
阅读量:5906 次
发布时间:2019-06-19

本文共 5653 字,大约阅读时间需要 18 分钟。

 

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击

 

一:io流中的装饰者设计模式

java.io包内的类太多了,简直是……"排山倒海"。你第一次(还有第二次和第三次)看到这些API发出"哇"的惊叹时,放心,你不是唯一受到惊吓的人。现在,你已经知道装饰者模式,这些I/O的相关类对你来说应该更有意义了,因为其中许多类都是装饰者。下面是一个典型的对象集合,用装饰者来将功能结合起来,以读取文件数据:

我们来看一下下面的这张类图

你可以发现,和星巴兹的设计相比,java.io其实没有多大的差异。我们把java.ioAAPI范围缩小,让你容易查看它的文件,并组合各种"输入"流装饰者来符合你的用途。

你会发现"输出"流的设计方式也是一样的。你可能还会发现Reader/Writer流(作为基于字符数据的输入输出)和输入流/输出流的类相当类似(虽然有一些小差异和不一致之处,但是相当雷同,所以你应该可以了解这些类)。

但是JavaAI/O也引出装饰者模式的一个"缺点":利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成使用此API程序员的困扰。但是,现在你已经了解了装饰者的工作原理,以后当使用别人的大量装饰的API时,就可以很容易地辨别出他们的装饰者类是如何组织的,以方便用包装方式取得想要的行为。

1.1,下面我们结合着BufferedInputStream和 BufferedOutputStream来分析一下装饰着设计模式代码很简单,主要看得就是它的源码

public class Test {

    public static void copyMp3() {

         try {

              FileInputStream fi = new FileInputStream("audio.mp3");

              BufferedInputStream buf = new BufferedInputStream(fi);

              FileOutputStream fio = new FileOutputStream("audioCapy.mp3");

              BufferedOutputStream buo = new BufferedOutputStream(fio);

              int ch = 0;

              while ((ch = buf.read()) != -1) {

                   buo.write(ch);

              }

              buf.close();

              buo.close();

         } catch (FileNotFoundException e) {

              e.printStackTrace();          } catch (IOException e) {

              e.printStackTrace();

         }

    }

}

BufferedInputStream buf = new BufferedInputStream(new FileInputStream("audio.mp3"));

我们来看一下这行代码

private static int defaultBufferSize = 8192;

public BufferedInputStream(InputStream in) {

this(in, defaultBufferSize);

}

初始化的时候就会进来这个方法中。

在进一层可以看到这行代码,意思就是把buf的数组长度复制为8192

public BufferedInputStream(InputStream in, int size) {

super(in);

if (size <= 0) {

throw new IllegalArgumentException("Buffer size <= 0");

}

buf = new byte[size];

}

下面我们来看这行代码。

buf.read()

public synchronized int read() throws IOException {

if (pos >= count) {

fill();

if (pos >= count)

return -1;

}

return getBufIfOpen()[pos++] & 0xff;

}

private byte[] getBufIfOpen() throws IOException {

byte[] buffer = buf;

if (buffer == null)

throw new IOException("Stream closed");

return buffer;

}

实际上返回的getBufIfOpen就是我们上面构造方法中的初始化的数组8192 下面我们来看fill()的方法

private void fill() throws IOException {

byte[] buffer = getBufIfOpen();

if (markpos < 0)

pos = 0;/* no mark: throw away the buffer */

else if (pos >= buffer.length)/* no room left in buffer */

if (markpos > 0) {

/* can throw away early part of the buffer */

int sz = pos - markpos;

System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz;

markpos = 0;

} else if (buffer.length >= marklimit) {

markpos = -1;/* buffer got too big, invalidate mark */

pos = 0;/* drop buffer contents */

} else {

/* grow buffer */

int nsz = pos * 2;

if (nsz > marklimit)

nsz = marklimit;

byte nbuf[] = new byte[nsz];

System.arraycopy(buffer, 0, nbuf, 0, pos);

if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {

// Can't replace buf if there was an async close.

// Note: This would need to be changed if fill()

// is ever made accessible to multiple threads.

// But for now, the only way CAS can fail is via close.

// assert buf == null;

throw new IOException("Stream closed");

}

buffer = nbuf;

}

count = pos;

int n = getInIfOpen().read(buffer, pos, buffer.length - pos);

if (n > 0)

count = n + pos;

}

我们来看getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码,具体的逻辑实现我们先不管,主要就是研究装饰者设计模式的。

private InputStream getInIfOpen() throws IOException {

InputStream input = in;

if (input == null)

throw new IOException("Stream closed"); return input;

}

在这里我们就确定了getInIfOpen是要返回的就是BufferedInputStream buf = new

BufferedInputStream(new FileInputStream("audio.mp3"));中的FileInputStream,现在我们去 fileinputstream中来找read(buffer, pos, buffer.length - pos)方法。

protected volatile InputStream in;

public int read(byte b[], int off, int len) throws IOException {

return in.read(b, off, len);

}

这个时候我们就可以看到这里的in就是inputStream最里面的核心的要被装饰的类。

现在我们在到inputStream的源码中来可以看到就是这样的。

public int read(byte b[], int off, int len) throws IOException {

if (b == null) {

throw new NullPointerException();

} else if (off < 0 || len < 0 || len > b.length - off) {

throw new IndexOutOfBoundsException();

} else if (len == 0) {

return 0; }

int c = read();

if (c == -1) {

return -1;

}

b[off] = (byte)c;

int i = 1;

try {

for (; i < len ; i++) {

c = read();

if (c == -1) {

break;

}

b[off + i] = (byte)c;

}

} catch (IOException ee) {

}

return i;

}

从上面的一整套的逻辑我们可以看到,BufferedInputStream的read方法扩展了核心的类 inputStream的功能,这个就是典型的装饰着设计模式,其实io流中有都是基于

InputStream的装饰着模式的扩张的应用的。

1.2,下面我们自己来定义一个流的类基于BufferedInputStream的在装饰

就是把首字符变成小写的。

LowerCaseInputStream.java

package com.DesignPatterns.ac.decorator_io; import java.io.*; public class LowerCaseInputStream extends FilterInputStream {

    public LowerCaseInputStream(InputStream in) {

         super(in);

    }

    public int read() throws IOException {

         int c = in.read();

         return (c == -1 ? c : Character.toLowerCase((char) c));

    }

    public int read(byte[] b, int offset, int len) throws IOException {

         int result = in.read(b, offset, len);

         for (int i = offset; i < offset + result; i++) {

              b[i] = (byte) Character.toLowerCase((char) b[i]);

         }

         return result;

    }

}

Test

package com.DesignPatterns.ac.decorator_io; import java.io.*;

public class InputTest {

    public static void main(String[] args) throws IOException {

         int c;

         try {

              InputStream in = new LowerCaseInputStream(new

BufferedInputStream(new FileInputStream("test.txt")));

              while ((c = in.read()) >= 0) {

                   System.out.print((char) c);

              }

              in.close();

         } catch (IOException e) {

              e.printStackTrace();

         }

    }

}

in.read(b, offset, len)这一行代码的装饰着设计模式我们上面说过了,就不在说了,那我们就主要的来看这里的再次装饰的逻辑

for (int i = offset; i < offset + result; i++) {

              b[i] = (byte) Character.toLowerCase((char) b[i]);

         }

当经过一次装饰之后我们再次对输出的结果进行修改,相当于又套了一个马甲又多了一个功能。这个就是典型的装饰着设计模式。

 

假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击

 

fff

转载地址:http://etcpx.baihongyu.com/

你可能感兴趣的文章
关于 error: LINK1123: failure during conversion to COFF: file invalid or corrupt 错误的解决方案...
查看>>
PHP盛宴——经常使用函数集锦
查看>>
安装gulp及相关插件
查看>>
如何在Linux用chmod来修改所有子目录中的文件属性?
查看>>
Hyper-V 2016 系列教程30 机房温度远程监控方案
查看>>
笔记:认识.NET平台
查看>>
SCCM 2016 配置管理系列(Part8)
查看>>
我的友情链接
查看>>
python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列
查看>>
javascript继承方式详解
查看>>
lnmp环境搭建
查看>>
自定义session扫描器精确控制session销毁时间--学习笔记
查看>>
PHP队列的实现
查看>>
单点登录加验证码例子
查看>>
[T-SQL]从变量与数据类型说起
查看>>
occActiveX - ActiveX with OpenCASCADE
查看>>
BeanUtils\DBUtils
查看>>
python模块--os模块
查看>>
Java 数组在内存中的结构
查看>>
《关爱码农成长计划》第一期报告
查看>>