一: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, markpos = } markpos = pos = } int nsz = pos * if nsz = marklimit; byte nbuf[] System.arraycopy(buffer, if // 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 } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if count = n + pos; } |
我们来看getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码,具体的逻辑实现我们先不管,主要就是研究装饰者设计模式的。
private InputStream getInIfOpen() throws IOException { InputStream input = in; if throw } |
在这里我们就确定了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 } throw } return int c = read(); if return } b[off] int i = try for c = read(); if break; } b[off + i] } } } 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 super(in); } public int c = in.read(); return } public int result = in.read(b, offset, len); for b[i] } return result; } } |
Test
package com.DesignPatterns.ac.decorator_io; import java.io.*; public public 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]);
}
当经过一次装饰之后我们再次对输出的结果进行修改,相当于又套了一个马甲又多了一个功能。这个就是典型的装饰着设计模式。 fff
原文地址:https://www.cnblogs.com/qingruihappy/p/9693866.html