一. 装饰器模式(摘录)
装饰器模式又称为包装(Wrapper)模式。装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类的方式并不可取,在面向对象的设计中,我们应该尽量使用组合对象而不是继承对象来扩展和复用功能,装饰器模式就是基于对象组合的方式的。
优点:装饰器模式与继承关系的目的都是要扩展对象的功能,但是装饰器模式可以提供比继承更多的灵活性。装饰器模式允许系统动态决定贴上一个需要的装饰,或者除掉一个不需要的装饰。继承关系是不同,继承关系是静态的,它在系统运行前就决定了
通过使用不同的具体装饰器以及这些装饰类的排列组合,设计师可以创造出很多不同的行为组合
缺点:由于使用装饰器模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是另一方面,由于使用装饰器模式会产生比使用继承关系更多的对象,更多的对象会使得查错变得困难,特别是这些对象看上去都很像。
二. 装饰器模式结构:
装饰器模式以对客户端透明的方式动态地给一个对象附加上了更多的责任。换言之,角色对象在装饰前和装饰后有什么不同。装饰器模式可以在不用创建更多子类的情况下,将对象的功能加以扩展。
装饰器模式中的角色有:
1、Component:抽象构件角色 ,给出一个抽象接口,以规范准备接受附加责任的对象
2、ConcreteComponent具体构件角色,定义一个将要接受附加责任的类
3、Decorator:装饰角色,持有一个构建对象的实例,并定义一个与抽象构件接口一致的接口
4、ConcreteDecorator:具体装饰角色,负责给构建对象贴上附加的责任
三. 应用实例
场景举例:
1、来了一群顾客要吃晚饭,北京顾客
2、这群顾客吃完晚饭后的习惯有些不同,有些人喜欢抽烟、有些人喜欢喝茶等等
那么,按照装饰器模式,先抽象出抽象构件角色,Consumer接口:
public interface Consumer {
public void eatDinner();
}
具体构件角色,北京顾客:
public class BeijingConsumer implements Consumer{
@Override
public void eatDinner() {
System.out.println("北京顾客开始吃晚饭.....");
}
}
定义一个装饰器角色,具体的工作由具体装饰器去实现,这样,比如辽宁顾客吃晚饭后也抽烟或者喝喝茶,这两个动作就可以做到复用,装饰器角色定义为ConsumerDecorator,很简单,实现Consumer接口并持有Consumer的引用:
public class ConsumerDecorator implements Consumer {
protected Consumer consumer;
public ConsumerDecorator(Consumer consumer) {
this.consumer = consumer;
}
@Override
public void eatDinner() {
this.consumer.eatDinner();
}
}
最后定义具体装饰角色,抽烟顾客、喝茶顾客:
public class TeaDecorator extends ConsumerDecorator {
public TeaDecorator(Consumer consumer) {
super(consumer);
}
@Override
public void eatDinner() {
this.consumer.eatDinner();
System.out.println("drink tea after dinner.....");
}
}
public class SmokingDecorator extends ConsumerDecorator {
public SmokingDecorator(Consumer consumer) {
super(consumer);
}
@Override
public void eatDinner() {
this.consumer.eatDinner();
System.out.println("smoke after dinner.....");
}
}
最后调用方法:
public static void main (String[] args) {
BeijingConsumer consumer = new BeijingConsumer();
TeaDecorator teaConsumer = new TeaDecorator(consumer);
SmokingDecorator smokingConsumer = new SmokingDecorator(consumer);
teaConsumer.eatDinner();
smokingConsumer.eatDinner();
}
运行结果:
北京顾客开始吃晚饭.....
drink tea after dinner.....
北京顾客开始吃晚饭.....
smoke after dinner.....
例子说明:装饰器模式的两个功能点:
1. 客户端只定义了Consumer接口,并不关心具体实现;
2. 给BeijingConsumer增加上了喝茶和抽烟的动作,且喝茶和抽烟的动作,可以给其他地区的顾客复用。
这就是装饰器模式。
装饰器模式和适配器模式的区别
其实适配器模式也是一种包装(Wrapper)模式,它们看似都是起到包装一个类或对象的作用,但是它们使用的目的非常不一样:
1、适配器模式的意义是要将一个接口转变成另外一个接口,它的目的是通过改变接口来达到重复使用的目的
2、装饰器模式不要改变被装饰对象的接口,而是恰恰要保持原有的接口哦,但是增强原有接口的功能,或者改变元有对象的处理方法而提升性能
所以这两种设计模式的目的是不同的。