介绍
装饰(Decorator)模式有名包装(Wrapper)模式。装饰模式已对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
模式角色
装饰模式有以下角色:
- Component(抽象构件),给出一个抽象接口,规定这个被装饰类有哪些功能。
- ConcreteComponent(具体构件),实现这个抽象组件的所有功能。
- Decorator(抽象装饰),它持有一个Component 对象实例的引用。
- ConcreteDecorator(抽象装饰),具体的装饰器实现者,负责实现装饰器角色定义的功能。
模式结构图
模式实现
/**
* 抽象构建
*/
public interface DecoratorComponent {
// 逻辑或业务
public void doSomething();
}
/**
* 具体构建
*/
public class ConcreteDecoratorComponent implements DecoratorComponent {
public ConcreteDecoratorComponent() {
}
@Override
public void doSomething() {
}
}
/**
* 抽象装饰
*/
public class Decorator implements DecoratorComponent {
private DecoratorComponent component;
public Decorator() {
}
public Decorator(DecoratorComponent component) {
this.component = component;
}
@Override
public void doSomething() {
// doSomething之前 可以做一些业务逻辑
component.doSomething();
// doSomething之后 可以做一些业务逻辑
}
}
/**
* 具体装饰
*/
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator() {
}
public ConcreteDecorator(DecoratorComponent component) {
super(component);
}
@Override
public void doSomething() {
// doSomething之前 可以做一些业务逻辑
super.doSomething();
// doSomething之后 可以做一些业务逻辑
}
}
模式对象图
模式对象图介绍,如:
// 是不是和我们平时使用Java的IO流时很像呢,用各种包装流来包装一个具体的流....
new Decorator1(
new Decorator2(
new Decorator3(
new ConcreteComponent()
)
)
);
透明的装饰模式
class DecoratorClient {
public static void main(String[] args) {
DecoratorComponent c = new ConcreteDecoratorComponent();
DecoratorComponent c1 = new ConcreteDecorator1(c);
DecoratorComponent c2 = new ConcreteDecorator2(c1);
c2.doSomething();
}
}
透明的装饰模式要求ConcreteDecorator里面***不可以***有Component里面所没有的方法。并且在要求程序不要声明一个ConcreteDecorator类型的变量,应当声明一个Component类型的变量。
半透明的装饰模式
class DecoratorClient {
public static void main(String[] args) {
DecoratorComponent c = new ConcreteDecoratorComponent();
ConcreteDecorator1 c1 = new ConcreteDecorator1(c);
ConcreteDecorator2 c2 = new ConcreteDecorator2(c1);
c2.doSomething();
}
}
在实际使用中,大多数装饰模式都是“半透明的装饰模式”。半透明的装饰模式允许ConcreteDecorator新增方法,在程序使用时声明一个ConcreteDecorator类型的变量,就可以用该类新增的方法。
透明的装饰模式与半透明的装饰模式例子,这里
模式退化
- 如果没有抽象的Componet类,而只有ConcreteComponent类,那么Decorator类经常可以是ConcreteComponent的一个子类。模式结构图如下:
- 如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。甚至在只有两个ConcreteDecorator类的情况下,都可以这么做。但是如果ConcreteDecorator类的数目大于三的话,使用一个单独的Decorator来区分抽象和具体的责任就是必要的了。
模式使用场景
- 需要扩展一个类的功能,或给一个类增加或附加责任。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
模式优缺点
主要优点:
- 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
- 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为,比如在I/O系统中,我们直接给BufferedInputStream的构造器直接传一个InputStream就可以轻松构件一个带缓冲的输入流,如果需要扩展,我们继续“装饰”即可。
- 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。
主要缺点:
- 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程序上影响程序的性能。
- 装饰模式提供了一种比继承更加灵活机动的解决方案,但同时也意味着比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。