1 设计模式介绍
装饰器模式(Decorator Pattern),又叫作包装器模式(Wrapper Pattern),指在不改变原有对象结构的情况下,动态地给对象增加一些额外功能的职责。属于对象结构型模式。
1.1 与代理模式的区别
装饰器模式强调自身功能的扩展,是代理模式的一个特殊应用。
代理模式强调对代理过程的控制。
1.2 装饰器模式的结构
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能增多,子类会很膨胀。
如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并且保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。
装饰器主要包含四个角色:
抽象构件(Component):可以是一个接口或者抽象类,充当装饰类的原始对象,规定了被装饰的行为。
具体构建(Concrete Component):实现/继承Component的一个具体对象,即被装饰对象。通过装饰角色为其添加一些职责。
抽象装饰器(Decorator): 实现/继承Component。其内部必然有一个属性指向Component,可以通过其子类扩展具体组件的功能。
具体装饰器(ConcreteDecorator): Decorator的具体实现类,并给具体构件对象添加附加责任,一般为其特有的功能。
图 装饰器模式UML
需求描述:对前端传递的数据需要对字段进行校验,比如,非空,日期校验等。
public class DecoratorTest {
/**
* 校验器
*/
interface Verifier {
boolean verify(Object object);
}
/**
* 网络请求校验器
*/
static class RequestVerifier implements Verifier{
@Override
public boolean verify(Object object) {
return object != null; //非空校验
}
}
/**
* 校验器装饰器
*/
static class VerifierDecorator implements Verifier {
private Verifier verifier;
public VerifierDecorator(Verifier verifier) {
this.verifier = verifier;
}
@Override
public boolean verify(Object object) {
return verifier.verify(object);
}
}
/**
* 日期校验器
*/
static class DateVerifierDecorator extends VerifierDecorator {
public DateVerifierDecorator(Verifier verifier) {
super(verifier);
}
@Override
public boolean verify(Object object) {
if(super.verify(object)) return dateVerify(object);
return false;
}
private boolean dateVerify(Object object) {
return object instanceof Date;
}
}
/**
* Integer 校验器
*/
static class IntegerVerifierDecorator extends VerifierDecorator {
public IntegerVerifierDecorator(Verifier verifier) {
super(verifier);
}
@Override
public boolean verify(Object object) {
if(super.verify(object)) return integerVerify(object);
return false;
}
private boolean integerVerify(Object object) {
return object instanceof Integer;
}
}
public static void main(String[] args) {
String obj0 = null;
String obj1 = "hello java";
Date obj2 = new Date();
Integer obj3 = 1;
Verifier requestVerifier = new RequestVerifier();
Verifier dateVerifier = new DateVerifierDecorator(requestVerifier);
System.out.println("dateVerifier");
System.out.println(obj0 + ":" + dateVerifier.verify(obj0));
System.out.println(obj1 + ":" + dateVerifier.verify(obj1));
System.out.println(obj2 + ":" + dateVerifier.verify(obj2));
System.out.println(obj3 + ":" + dateVerifier.verify(obj3));
System.out.println("----------------------------");
Verifier integerVerifier = new IntegerVerifierDecorator(requestVerifier);
System.out.println("integerVerifier");
System.out.println(obj0 + ":" + integerVerifier.verify(obj0));
System.out.println(obj1 + ":" + integerVerifier.verify(obj1));
System.out.println(obj2 + ":" + integerVerifier.verify(obj2));
System.out.println(obj3 + ":" + integerVerifier.verify(obj3));
// 运行结果:
// dateVerifier
// null:false
// hello java:false
// Sun Nov 06 11:18:26 CST 2022:true
// 1:false
// ----------------------------
// integerVerifier
// null:false
// hello java:false
// Sun Nov 06 11:18:26 CST 2022:false
// 1:true
}
}
1.3 优缺点
优点:在不改变现有对象结构的情况下,动态地给对象增加一些职责(额外功能)。
缺点:如果对于一个类型装饰的类的扩展功能太多,那么将会产生很多的小类。增加了程序的复杂性,不易排错。
二 java I/O 系统与装饰器模式
编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或是有能力就收数据的接收端。“流”屏蔽了实际的I/O设备中处理数据的细节。
Java类库中的I/O类分成输入和输出两部分,通过继承,任何自InputStream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。但是。我们通常不会用到这些方法,它们之所以存在是因为别的类可以使用它们,以便提供更有用的接口。因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能。这就是装饰器模式。
图 InputStream 继承结构
需求描述:创建一个缓存读取文件的inputStream。
InputStream is = new FileInputStream(“filePath”);
InputStream bufferIs = new BufferInputStream(is);
三 使用场景
1)当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
2)当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
3)当对象的功能要求可以动态地添加,也可以再动态地撤销时。