装饰模式的定义与特点
装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
采用装饰模式扩展对象的功能比采用继承方式更加灵活。 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
装饰模式结构图
- Component : 定义一个抽象类,定义规范
- ConcreteComponent : 被修饰类
- Decoarter : 装饰类
- ConcreteDecoratorA : 装饰具体实体类
- ConcreteDecoratorB : 装饰具体实体类
代码实现
Component实现
public abstract class Component {
//定义统一抽象方法,进行统一管理
public abstract void operator();
}
ConcreteComponent实现
public class ConcreteComponent extends Component{
@Override
public void operator() {
System.out.println("这是一个被装饰的类");
}
}
Decorator实现
public class Decorator extends Component {
private Component component;
//构造函数传入被装饰类
public Decorator(Component component) {
this.component = component;
}
//委托给被修饰类调用
@Override
public void operator() {
component.operator();
}
}
ConcreteDecoratorA实现
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operator() {
//调用被装饰类的实现
super.operator();
//调用装饰类中的实现
System.out.println("具体的装饰类A");
}
}
ConcreteDecoratorB实现
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operator() {
//调用被装饰类的实现
super.operator();
//调用装饰类中的实现
System.out.println("具体的装饰类B");
}
}
实现效果
一个简单的装饰模式就是如上所示,具体的装饰代码在ConcreteDecoratorA/ConcreteDecoratorB中实现
传入的被装饰类Component将operator方法的调用 交给 装饰实现类
以上,一个简单的装饰设计模式代码就完成了。
jdk中使用示例
jdk中的InputStream就是使用了装饰设计模式
InputStream设计结构
初始结构图如下(并不完整,大概看一下),设计之初始,InputStream有几个子类,进行流的操作
随着时代的发展,慢慢的这些类效率就不足了,需要再进行增强,如果需要对字节进行缓存来提升效率,就会变成如下所示:
增强不久,发现又功能不足了,需要PushBack(回退)操作,怎么办,再添加类吗?先看下添加后的效果:
区区两次增强,就导致类爆增,后续再增强几次的话,那根本就没法看了,会直接爆炸的。
这种情况下怎么办?就新增了FilterInputStream(效果为上面的Decorator )这个类,效果图:
FilterInputStream就是上面的Decorator,直到装饰作用
BufferedInputStream就是装饰的具体实现类,对被装饰类起到增强作用
PushBackInputStream与BufferedInputStream同理,增强的功能不同
FileInputStream就是被装饰类
UML结构图如下所示:
如上图,可以看出,InputStream就是使用的装饰设计模式
代码演示如下
创建个aaa.txt文件放在D:\filetest目录下
public class TestUser {
public static void main(String[] args) throws IOException {
//创建被装饰类(读取aaa.txt文件)
FileInputStream fileInputStream = new FileInputStream("D:\\filetest\\aaa.txt");
//装饰类(传入被装饰类)
FilterInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
byte[] bytes = new byte[1024];
int len = 0;
//bufferedInputStream.read(bytes) 方法是BufferedInputStream类中的read(bytes)方法
//对FileInputStream直到增强作用
while ( (len = bufferedInputStream.read(bytes)) != -1){
//输出txt文件内容
System.out.println(new String(bytes));
}
}
}
效果如下:
除了InputStream以外,还有DataSource同样也是使用了装饰模式,总体来说,在jdk以及spring中,这是一种比较常见的设计模式。