发布时间:2020-07-19 20:35:14来源:阅读:
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
业务场景:现我们现在模拟这样一个场景,我们点了一杯奶茶,然后给奶茶中加了冰块,加了珍珠,最后我们还想再给加点红豆,这里加红豆就使用了装饰者。
我们先来创建一个奶茶的抽象类,这个就是上面的Component
角色
public interface MilkyTea {
public void recipe();
}
我们再来创建要给奶茶的具体子类,相当于ConcreteComponent
public class MilkyTeaA implements MilkyTea {
@Override
public void recipe() {
System.out.println("老板来一杯奶茶,加冰块");
}
}
接下来创建一个装饰类,相当于Decorator
public class Decorator implements MilkyTea {
private MilkyTea milkyTea;
public void setMilkyTea(MilkyTea milkyTea) {
this.milkyTea = milkyTea;
}
@Override
public void recipe() {
milkyTea.recipe();
}
}
创建装饰类的子类,添加珍珠,相当于ConcreteDecorator
public class MilkyTeaADecorator extends Decorator {
@Override
public void recipe() {
super.recipe();
//对现有类进行功能增强
recipeZZ();
}
// 加珍珠
public void recipeZZ() {
System.out.println("老板再加点珍珠吧");
}
}
创建装饰者的子类,添加红豆,相当于ConcreteDecorator
public class MilkyTeaBDecorator extends Decorator {
@Override
public void recipe() {
super.recipe();
recipeHD();
}
public void recipeHD() {
System.out.println("老板你再给加点红豆吧");
}
}
最后我们测试一下看下结果:
public class Test {
public static void main(String[] args) {
MilkyTeaA milkyTea = new MilkyTeaA();
MilkyTeaADecorator milkyTeaA = new MilkyTeaADecorator();
MilkyTeaBDecorator milkyTeaB = new MilkyTeaBDecorator();
milkyTeaA.setMilkyTea(milkyTea);
milkyTeaB.setMilkyTea(milkyTeaA);
milkyTeaB.recipe();
}
}
在JDK
中,IO部分的很多类用到了装饰器模式。
InputStream
作为抽象构件(Component
),其下面大约有如下几种具体基础构件(ConcreteComponent
),从不同的数据源产生输入:
ByteArrayInputStream
,从字节数组产生输入;
FileInputStream
,从文件产生输入;
StringBufferInputStream
,从String对象产生输入;
PipedInputStream
,从管道产生输入;
SequenceInputStream
,可将其他流收集合并到一个流内;
FilterInputStream
作为装饰器在JDK
中是一个普通类,其下面有多个具体装饰器比如BufferedInputStream
、DataInputStream
等。我们以BufferedInputStream
为例,使用它就是避免每次读取时都进行实际的写操作,起着缓冲作用。我们可以在这里稍微深入一下,站在源码的角度来管中窥豹。
FilterInputStream内部封装了基础构件:
protected volatile InputStream in;
而BufferedInputStream
在调用其read()读取数据时会委托基础构件来进行更底层的操作,而它自己所起的装饰作用就是缓冲,在源码中可以很清楚的看到这一切:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -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;
// 看这行就行了,委托基础构件来进行更底层的操作
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
这部分的代码很多,这里我们没有必要考虑这段代码的具体逻辑,只需要看到在BufferedInputStream的read方法中通过getInIfOpen()获取基础构件从而委托其进行更底层的操作(在这里是读取单个字节)就可以说明本文所要说的一切了。
至于I/O类库中的其他设计诸如OutputStream、Writer、Reader,是一致的,这里就不再赘述了。
但是也有其自身的缺点:
多层的装饰是比较复杂的。为什么会复杂?你想想看,就像剥洋葱一样,你剥到最后才发现是最里层的装饰出现了问题,可以想象一下工作量。这点从我使用Java I/O的类库就深有感受,我只需要单一结果的流,结果却往往需要创建多个对象,一层套一层,对于初学者来说容易让人迷惑。
理论的学习还是为了实践。实战中如果需要用到装饰器模式,可以从模仿 Java IO 部分的装饰器模式开始。模仿是创新的开始。
3dmax场景助手(3d建模类场景设计管理工) 4.1.10 最新版
0.17MB
Win7官方主题精选-装饰厅堂 v1.0
9.39 MB
altium designer 10(多功能电路设计软件)破解版
3.43G
autocad2014(cad设计软件) 免费版
1505.28MB
autocad2016(计算机辅助设计软件)中文破解版
1884.16MB
powerdesigner(数据库设计工具)v16.5 最新版
615.07MB
protel dxp(pcb线路板设计软件)v2021 免费版
1.6M
开贝设计下载
89.3M
2345王牌浏览器下载
65.5M
ceb文件阅读器下载
42.6M
h264播放器(视频播放软件)v6.2.0 中文版
11.2M
ip修改器下载
486KB
pcsx2模拟器下载
12.9M
swf播放器下载
2.5MB
txt分割器(文本处理工具)v3.5 官方版
0.35MB
vcf通讯录编辑器下载
1.77MB
vplayer(影音播放器) v4.4.4 官方版
55MB
爱思助手(播放器工具) 7.98.25 最新版
119.2M
acd看图软件下载
1.76 MB
coreldraw9下载
315.3K
2020-02-19
扬天系列机型(V360/V460/V560/B460)port locker功能使用方法
Win10升级1607周年更新的几种方法
联想KUF1256 USB Fingerprint Keyboard (指纹键盘)驱动程序下载链接
Docker命令行参考(2) – dockerd启动docker daemon
docker部署Elasticsearch集群
基于分布式框架Jepsen的X-Cluster正确性测试
Win7如何清除资源管理器中地址栏中的历史记录
Lenovo一键恢复4.0和4.5使用图解
联想摄像头随机软件能否保存视频捕捉属性以及视频捕捉参数?