设计模式(5)------装饰者设计模式(IO流的应用)

一: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]);

}

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

原文地址:https://www.cnblogs.com/qingruihappy/p/9693866.html

时间: 2024-10-10 09:52:23

设计模式(5)------装饰者设计模式(IO流的应用)的相关文章

设计模式学习之装饰模式:IO流的装饰器

IO流的装饰器 题目分析:通过对java的io系列类分析得知,java的io流使用了设计模式中的装饰模式,以动态的给一个对象增加职责,能够更加灵活的增加功能.通过看io的源代码得知FilterOutputStream类继承了OutputStream类并拥有父类的一个对象,它和父类具有组合聚合的关系.因此要实现我们自己的加密类只需扩展FilterOutputStream类重写它的wite方法即可 UML图: 源代码: package com.cmc import java.io.FilterOut

设计模式之---装饰器设计模式

职责:动态的为一个对象增加新的功能 装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能.使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀. 实现细节: ——Component抽象构件角色:真实对象和装饰对象有相同的接口.这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互. ——ConcreteComponent具体构件角色(真实对象):io流中的FileInputStream. FileOutputStream ——Decorator装饰角色

设计模式(4)------装饰者设计模式

一,需求 现在在星巴克咖啡店,有4中咖啡,有无数种的配料,怎样算出一种咖啡随机加配料的价格,加配料肯能是一种,也可能是多种,而且也有可能是重复的. 如图: 假如现在根据每一个不同的配料新增一个类的话会是怎么样的呢,看图. 是不是要爆炸了呢. 那怎么解决这个问题呢. 好了,现在我们来修改一下这个设计好吧!就来试试看.先从Beverage基类下手,加上实例变量代表是否加上调料(牛奶.豆浆.摩卡.奶泡--) 上面的修复可能出现什么问题呢?调料价钱的改变会使我们更改现有代码. 一旦出现新的调料,我们就需

设计模式之装饰器模式io的小入门(十一)

装饰器模式详解地址 原文总结 定义: 在不必改变原类文件和使用继承的情况下, 动态的扩展一个对象的功能. 通过创建一个包装对象, 也就是装饰来包裹真实的对象 部分详解提示 看了一些文档, 装饰器模式非常依赖构造器 与 重写方法 装饰器模式的特点: 不改变原来的类 , 不使用继承 , 动态扩展 流这块除了文件上传下载使用过, 确实用的太少了这里继续复习下最简单的文件上传 文件目录的创建 目录的是否存在没有就创建 不推荐: 年/月/日 一般没什么用户权限的图片之类的不过 推荐: 模块/用户/模块/年

10.9-全栈Java笔记:装饰器模式构建IO流体系

装饰器模式 装饰器模式是GOF23种设计模式中较为常用的一种模式.它可以实现对原有类的包装和装饰,使新的类具有更强的功能. 我这里有智能手机Iphone, 我们可以通过加装投影组件,实现原有手机功能的扩展.这就是一种"装饰器模式". 我们在未来普通人加装"外骨骼"装饰,让普通人具有力扛千斤的能力,也是一种"装饰器模式". [图] 手机经过投影套件"装饰后",成为功能更强的"投影手机" [示例1]装饰器模式代

Java学习总结(8)—内存流,打印流,对象流,RandomAccessFile,装饰者设计模式

一.内存流 内存流主要用来操作内存 BytearrayInputStream和ByteArrayOutputStream输入和输出可以把文件作为数据源,也可以把内存作为数据源 (1)ByteArrayInputStream主要完成将内容从内存读入到程序中,而ByteArrayOutputStream的主要功能是是将数据写入到内存中 (2)注意:因为这两个流没有使用系统资源,所以不用关闭,也不需要抛出异常 内存操作示意图 (1)从程序中读:程序<-ByteArrayInputStream<-内存

文件IO流的修饰者设计模式

public class Page3 { /** * 装饰者设计模式 * InputStream为父类下面有7个直接子类 * FileInputStream ByteArrayInputStream StringBufferInputStream * PipedInputStream ObjectInputStream SequenceInputStream * FilterInputStream * FilterInputStream下有三个修饰类 * BufferedInputStream

设计模式之装饰者模式

设计模式系列都是学习HeadFirst设计模式得出的学习心得,中间的例子也会采用书中的例子.这里有必要解释一下,在下面星巴克咖啡的例子中,有几种基本的咖啡,还有牛奶.豆浆等等可以向咖啡中添加,这里说明防止下面不懂. 今天我们来了解一下装饰者模式. 回想一下java的io包,各种stream排上倒海,初学者根本分不清楚到底怎么用,眼花缭乱.其实,它的实验遵循了装饰者设计模式.顾名思义,装饰者就可以简单的理解成用一个东西来装饰另一个东西.比如,你要做鱼吃,在你做好出国之后需要加入香菜.我们就可以简单

设计模式--装饰者设计模式(Decorator)

装饰者模式又叫包装模式. 通过另一个对象来扩展自己的行为,在不破坏类的封装的情况下,实现松耦合,易扩展的效果. 抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口可以给这些对象动态地添加职责. 具体组件角色:为抽象组件的实现类,是定义了一个具体的对象,也可以给这个对象添加一些职责. 抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator存在的. 具体装饰角色