一个男人的设计模式:装饰模式
类图结构

模式描述
装饰者(Decorator)与被装饰者(ConcreteComponent)需要实现统一抽象接口(Component),这样可以保证装饰者和被装饰者有统一的接口规范,即装饰者(Decorator)和被装饰者(ConcreteComponent)的使用方法一致。同时装饰者(Decorator)需要组合一个统一抽象接口(Component)的实例对象,调用装饰者某个方法时,会进行一定的增强处理(装饰)后,再调用组合的统一抽象接口(Component)的实例对象来具体实现最基本的功能。
装饰模式以对客户端透明的方式【装饰者(Decorator)与被装饰者(ConcreteComponent)实现统一抽象接口】扩展对象的功能,是继承关系的一个替代方案。装饰模式可以在不创建更多子类的情况下,将对象的功能加以扩展。
统一抽象接口 Component
public interface Component {
public void doSomething();
}
被装饰者 ConcreteComponent
public class ConcreteComponent implements Component{
public void doSomething() {
System.out.println("doSomething");
}
}
装饰者 Decorator
public abstract class Decorator implements Component {
private Component component;
Decorator(Component component){
this.component = component;
}
public void doSomething() {
component.doSomething();
}
}
装饰者子类 ConcreteDecorator
public class ConcreteDecorator extends Decorator {
ConcreteDecorator(Component component) {
super(component);
}
@Override
public void doSomething() {
System.out.println("before doSomething ");
super.doSomething();
System.out.println("after doSomething ");
}
}
测试代码
public class Client {
public static void main(String[] args) {
//ConcreteDecorator 对ConcreteComponent进行进一步封装
Decorator decorator = new ConcreteDecorator(new ConcreteComponent());
//调用方式和ConcreteComponent的调用方式一样
decorator.doSomething();
}
}
before doSomething
doSomething
after doSomething
装饰模式在JavaIO体系中的应用
Java的I/O库提供了一个称为连接的机制,可以将流与另一个流首尾相接,形成一个流管道的连接,这种机制实际上是一种被称为Decorator(装饰)设计模式的应用。通过流的链接,可以动态增加流的功能,而这种功能的增强是通过组合一些流的基本功能而动态获取的,这就提高了流使用灵活性。
| 抽象接口 | 被装饰者 | 装饰者 | 装饰者实现类 | |
|---|---|---|---|---|
| 装饰模式 | Component | ConcreteComponent | Decorator | ConcreteDecorator |
| IO体系 | InputStream | FileInputStream(节点流均可) | FilterInputStream(过滤流) | BufferedInputStream(过滤流子类) |
JAVA I/O流
Java程序通过流来完成输入输出,流是生产或消费消息的抽象。java中流的实现是在java.io包定义的类层次接口。
输入/输出时相对于程序来说的。程序在使用数据时要么作为数据源,要么作为数据目的地,所作为数据源,即数据的提供者,则为输出流,否则为输入流。
| 字节流 | 字符流 | |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
节点流:从特定的地方读写的流类,例如:磁盘或一块内存区域
过滤流:使用节点流作为输出或输出,过滤流是使用一个已经存在的输入流或输出流连接创建的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQgoCGnN-1613828623383)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210220202109310.png)]
过滤流
在InputStream和OutputStream的子类中派生了FilterInputStream和FilterOutputStream过滤流,本质上这一类过滤流是对InputStream和OutputStream的其它子类进行一层封装(装饰)。
例子

使用节点流FileInputStream从文件中获取字节流,使用过滤器流BufferedInputStream对FileInputStream进行增强(装饰),使得该流具备了缓冲功能,再通过DataInputStream对已经具有缓冲功能的进行再次增强(装饰),使得具备了读取java基本类型的功能。
BufferedInputStream对FileInputStream的read()装饰
统一抽象接口 InputStream
public abstract class InputStream implements Closeable {
/**
抽象统一接口,其它接口省略不写
*/
public abstract int read() throws IOException;
}
被装饰者 FileInputStream
public class FileInputStream extends InputStream{
/**
被装饰者的实现方法
*/
public int read() throws IOException {
return read0();
}
/**
调用原生方法
*/
private native int read0() throws IOException;
}
装饰者FilterInputStream
public class FilterInputStream extends InputStream {
/**
组合抽象接口的实例对象字段
* The input stream to be filtered.
*/
protected volatile InputStream in;
//持有节点流对象
protected FilterInputStream(InputStream in) {
this.in = in;
}
//读数据
public int read() throws IOException {
return in.read();
}
}
装饰者BufferedInputStream
public class BufferedInputStream extends FilterInputStream {
/**
缓存字节的数组对象,字节流会保存在该数组中,当read时会获取素组中的数据
* The internal buffer array where the data is stored. When necessary,
* it may be replaced by another array of
* a different size.
*/
protected volatile byte buf[];
public int read() throws IOException {
return in.read();
}
//构造函数
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
//构造函数保存节点流对象FileInputStream
public BufferedInputStream(InputStream in, int size) {
//保存节点流对象
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
//第一步
public synchronized int read() throws IOException {
if (pos >= count) {
//将节点流数据读入缓存数组buffer中
fill();
if (pos >= count)
return -1;
}
//从缓存数组buffer中获取1字节数据
return getBufIfOpen()[pos++] & 0xff;
}
//第二步
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 if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
//第三步
//这里就是调用最初构造 传入的节点流对象,这里是FileInputStream 这里就调用了FileInputStream的reader方法来将数据读入buffer中
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
//获得在构造过滤流时传入的节点流对象,这里是FileInputStream
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
}
测试代码
public class Client {
public static void main(String[] args) throws Exception{
//采用装饰模式读取一个字符
FilterInputStream filterInputStream = new BufferedInputStream(new FileInputStream("testdata.txt"));
System.out.println("have Buffer first char:"+(char)filterInputStream.read());
filterInputStream.close();
//采用非装饰模式读取一个字符
InputStream inputStream = new FileInputStream("testdata.txt");
System.out.println("no Buffer first char:"+(char)inputStream.read());
inputStream.close();
}
}
have Buffer first char:d
no Buffer first char:d
装饰模式以对客户端透明的方式【装饰者(Decorator)与被装饰者(ConcreteComponent)实现统一抽象接口】扩展对象的功能,是继承关系的一个替代方案。装饰模式可以在不创建更多子类的情况下,将对象的功能加以扩展。
以上,感谢阅读!!!!!!!

本文详细介绍了装饰模式的概念、结构和工作原理,通过代码示例展示了如何使用装饰模式来扩展对象功能。此外,还探讨了装饰模式在Java IO系统中的应用,如BufferedInputStream对FileInputStream的装饰,以实现缓冲功能。装饰模式提供了一种替代继承的扩展机制,允许在不修改原有代码的基础上动态增加功能。
1390

被折叠的 条评论
为什么被折叠?



