装饰模式(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 Behaviour behaviour;
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();
}
}
//ConcreteDecorator类对应的类-NoonDecorator、NightDecorator类
//晚上
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 Test1 {
public static void main(String[] args) {
Behaviour behaviour = new XiaoMing();
behaviour = new NoonDecorator(behaviour);
behaviour = new NightDecorator(behaviour);
behaviour.process();
}
}
运行结果如下:
//主程序代码调整
public class Test2 {
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();
}
}
Test1和Test2 运行结果一致。
可以看出来,每个装饰的对象的实现和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
Imoprtant:
当系统需要新功能的时候,是向旧的类中添加新的代码。这些新的代码通常装饰了原有类的核心职责或主要行为。他们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。而装饰模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装他所需要装饰的对象,因此当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。最理想的情况,是包装装饰类之间彼此独立,这样就可以以任意的顺序进行组合了。
优点:
把类中的装饰功能从类中搬移去除,这样可以简化原有的类。
有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。