装饰器模式
概念
装饰器模式(Decorator)也叫包装器模式(Wrapper),属于结构型模式,用于动态的为对象添加功能。通常情况下给对象添加功能,要么直接修改对象,要么使用继承来扩展,也可以使用组合的方式。直接修改对象的方式显然是不合适的,如果使用继承的方式,极有可能会导致子类膨胀。在面向对象的设计中,一般使用组合的方式来扩展对象的功能。装饰器模式就是使用组合的方式来代替类继承的方式以扩展对象的功能,使得更加灵活,也避免了类型的快速膨胀。
类图
角色
Component:组件对象的接口,可以给这个对象动态的添加职责
ConcreteComponent:具体的组件对象,实现了组件的接口,该对象通常用作被装饰器装饰的原始的对象,可以给这个对象添加职责
Decorator:装饰器的父类,需要与组件接口一致,这里继承自Component主要是因为需要一个装饰器也可以被另一个装饰器装饰。
ConcreteDecorator:具体的装饰器类,实现具体要像被装饰对象添加的功能,用于装饰具体的组件对象或者另外一个具体的装饰器对象。
实例
Component对象
public abstract class Component {
public abstract void operation();
}
ConcreteComponent对象
public class ConcreteComponent extends Component {
public void operation() {
System.out.println("ConcreteComponent::operation");
}
}
Decorator对象
public abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public abstract void operation();
}
ConcreteDecoratorA对象
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
System.out.println("ConcreteDecoratorA::operation");
component.operation();
}
}
ConcreteDecoratorB对象
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
System.out.println("ConcreteDecoratorB::operation");
component.operation();
}
}
Client对象
public class Client {
public static void main(String[] args) {
Component c = new ConcreteComponent();
Decorator dA = new ConcreteDecoratorA(c);//给对象增加A功能
dA.operation();
Decorator dB = new ConcreteDecoratorB(dA);//给A添加B功能
dB.operation();
}
}
优缺点
装饰器模式降低了系统的耦合度,可以动态的增加或者删除对象的功能,并需要装饰的具体的组件和装饰类可以独立变化,以便增加新的功能。
优点:
扩展对象功能,比继承灵活,避免了类膨胀
可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类
缺点:
产生很多小对象,大量小对象占据内存,一定程度上影响性能
装饰模式如果出错,调试比较困难
Java中的装饰器模式
Java中最经典的装饰器模式便是IO类簇了。Java的IO分为字节流和字符流,又可以分为输入流和输出流。
字节流 | 字符流 | |
输入流 | InputStream StringBufferInputStream FileInputStream ByteArrayInputStream PipedInputStream ObjectInputStream SequenceInputStream FilterInputStream BufferedInputStream DataInputStream PushbackInputStream | Reader PipedReader CharArrayReader BufferedReader StringReader InputStreamReader FileReader FilterReader PushbackReader |
输出流 | OutputStream ByteArrayOutputStream FileOutputStream ObjectOutputStream PipedOutputStream FilterOutputStream DataOutputStream BufferedOutputStream | Writer PrintWriter PipedWriter CharArrayWriter StringWriter BufferedWriter OutputStreamWriter FileWriter FilterWriter |
字节流:InputStream对应Component;StringBufferInputStream,FilteInputStream,ByteArrayInputStream,PipedInputStream,对应ConcreteComponent;FilterInputStream对应Decorator;BufferedInputStream,DataInputStream,PushbackInputStream对应ConcreteDecorator;
字符流:Reader对应Component;PipedReader,CharArrayReader,StringReader对应ConcreteComponent;FilterReader对应Decorator;PushbackReader对应ConcreteDecorator;
InputStreamReader用于将字节流封装成字符流
字节流:从类图中可以很明显的看出,OutputStream对应Component;ByteArrayOutputStream,FileInputStream,ObjectOutputStream,PipedOutputStream对应于ConcreteComponent;FilterOutputStream对应Decorator;DataOutputStream,BufferedOutputStream对应ConcreteDecorator;
字符流:writer对应Component;PipedWriter,StringWriter,CharArrayWriter对应ConcreteComponent;BufferedWriter,PrintWriter,FilterWriter对应Decorator;不过这里的BufferedWriter和PrintWriter也可以认为是ConcreteDecorator。
这里还有个OutputStreamWriter类,可以看出用于将字节流封装成字符流的。
Android中的装饰器模式
Android中的Context,ContextImpl,Activity等便是使用了装饰器模式
这里的Context对应Component;ContextImpl对应ConcreteComponent;ContextWrapper对应Decorator;Service,Application,ContextThemeWrapper对应ConcreteDecortor。
ContextWrapper持有一个Context成员变量,再各个组件创建时会将ContextImpl赋给各个组件。