装饰模式(decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
起初看装饰模式时,我并没有太看懂是什么意思。。后来实际敲了一份代码,才渐渐明白是怎么回事。
装饰模式的基础有4个类:
- Componet类。定义了一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent类。定义了一个具体的对象,也可以给这个对象添加一些职责。
- Decorator类。装饰抽象类,继承了Component类,从外类来扩展Component类的功能,但对于Component类来说,是无需知道Decorator的存在的。
- ConcreteDecorator类。具体的装饰对象,起到给Component添加职责的功能。实际上会有多个装饰对象。
举例:
小明一天的生活,早上8点起床,然后去上班,晚上10点睡觉。
根据装饰模式的基础类,可以定义如下5个类:
- Component对应的类-Behaviour类
public interface Behaviour {
public void wakeUp();
public void doSth();
public void sleep();
public void process();
}
- ConcreteComponent对应的类-XiaoMing类
public class XiaoMing implements Behaviour {
@Override
public void wakeUp() {
System.out.println("早上8点起床");
}
@Override
public void doSth() {
System.out.println("去上班");
}
@Override
public void sleep() {
System.out.println("晚上10点睡觉");
}
@Override
public void process() {
wakeUp();
doSth();
sleep();
}
}
- Decorator类对应的类-Decorator类
public abstract class Decorator implements Behaviour {
private Person person;
public Decorator(Behaviour behaviour) {
this.behaviour = behaviour;
}
@Override
public void wakeUp() {
if (behaviour!= null) {
behaviour.wakeUp();
}
}
@Override
public void doSth() {
if (behaviour != null) {
behaviour.doSth();;
}
}
@Override
public void sleep() {
if (behaviour!= null) {
behaviour.sleep();
}
}
@Override
public void process() {
if (behaviour!= null) {
// 注意,一定不要写成behaviour.wakeUp();
// 否则无法调用具体的装饰对象中,重写的父类中的方法
wakeUp();
doSth();
sleep();
}
}
}
- ConcreteDecorator类对应的类-NoonDecorator、NightDecorator类
public class NoonDecorator extends Decorator {
public NoonDecorator(Behaviour behaviour ) {
super(behaviour);
}
public void relex() {
System.out.println("中午有点困,午休一下");
}
// 干完工作后再午休,因此添加在doSth方法后
@Override
public void doSth() {
super.doSth();
relex();
}
}
public class NightDecorator extends Decorator {
public NightDecorator(Behaviour behaviour ) {
super(behaviour );
}
public void eat() {
System.out.println("工作一天辛苦了,吃顿大餐");
}
// 睡觉前来顿大餐,因此添加在sleep方法前
@Override
public void sleep() {
eat();
super.sleep();
}
}
- 主程序
public class Test {
public static void main(String[] args) {
Behaviour behaviour = new XiaoMing();
behaviour = new NoonDecorator(behaviour);
behaviour = new NightDecorator(behaviour);
behaviour.process();
}
}
运行结果如下:
早上8点起床
去上班
中午有点困,午休一下
工作一天辛苦了,吃顿大餐
晚上10点睡觉
主程序还可以做如下调整:
public class Test {
public static void main(String[] args) {
Behaviour behaviour = new XiaoMing();
// behaviour = new NoonDecorator(behaviour);
// behaviour = new NightDecorator(behaviour);
// behaviour.process();
NoonDecorator d1 = new NoonDecorator(behaviour);
NightDecorator d2 = new NightDecorator(d1);
d2.process();
}
}
运行结果和上面的结果是一样的。
可以看出来,每个装饰的对象的实现和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
总结:
当系统需要新功能的时候,是向旧的类中添加新的代码。这些新的代码通常装饰了原有类的核心职责或主要行为,他们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。而装饰模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装他所需要装饰的对象,因此当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。最理想的情况,是包装装饰类之间彼此独立,这样就可以以任意的顺序进行组合了。