装饰器模式能够在不改变现有的类的情况下对现有的类进行包装,装饰器类与被装饰类可以完全解耦,摆脱相互依赖。对现有的类进行功能动态的增加。
下面在代码中使用装饰器模式完成一个小功能,理解一下装饰器模式思想。
假设有一个可拍照的接口,实现该接口的事物都可以拍照:
public interface PhotographAble {
void photograph();
}
人类可以拍照,他就实现了拍照的接口:
public class People implements PhotographAble {
@Override
public void photograph() {
System.out.println("this is a people");
}
}
假如说人在拍照前想穿上衣服那么通常的方法就是写一个ClothesPeople继承People,假如想穿一双鞋呢,又写一个ShoesPeople继承People,如果先穿鞋子又穿衣服呢又需要ShoesAndClothesPeople继承People,那先穿衣服又穿鞋呢又需要ClothesAndShoesPeople继承People,当功能越多时所有排列的可能就越多,那么就需要很多的子类去实现这些可能排列的功能,但是使用装饰器模式就没有这么复杂了。
我们首先定义了装饰器的抽象类也实现了可拍照接口:
public abstract class Decorator implements PhotographAble {
private PhotographAble photographAble;
public Decorator(PhotographAble photographAble) {
this.photographAble = photographAble;
}
@Override
public void photograph() {
photographAble.photograph();
}
}
定义具体的衣服装饰器类和鞋子装饰器类继承抽象的装饰器类,并在拍照前进行功能的增强:
public class ClothesDecorator extends Decorator {
public ClothesDecorator(PhotographAble photographAble) {
super(photographAble);
}
@Override
public void photograph() {
dress();
super.photograph();
}
private void dress(){
System.out.println("There are clothes");
}
}
public class ShoesDecorator extends Decorator {
public ShoesDecorator(PhotographAble photographAble) {
super(photographAble);
}
@Override
public void photograph() {
dress();
super.photograph();
}
private void dress(){
System.out.println("There are shoes");
}
}
现在可以测试一下所有的情况,在这里如何包装就是调用者自己控制了:
public class Main {
public static void main(String[] args) {
System.out.println("-----穿衣服拍照-----");
PhotographAble people1 = new People();
people1 = new ClothesDecorator(people1);
people1.photograph();
System.out.println("-----穿鞋拍照-----");
PhotographAble people2 = new People();
people2 = new ShoesDecorator(people2);
people2.photograph();
System.out.println("-----先穿衣服后穿鞋拍照-----");
PhotographAble people3 = new People();
people3 = new ShoesDecorator(people3);
people3 = new ClothesDecorator(people3);
people3.photograph();
System.out.println("-----先穿鞋后穿衣服拍照-----");
PhotographAble people4 = new People();
people4 = new ClothesDecorator(people4);
people4 = new ShoesDecorator(people4);
people4.photograph();
}
}
运行结果如下图:
值得注意的是装饰的顺序与代码的顺序是相反的,这点通过分析代码就可以得出,也可以想象为包粽子,最后包的粽叶肯定是最外的,也就是最先看到的嘛。
装饰器模式优点:
- 不改变原有类的基础上对原有类进行增强,装饰类与原有类完全解耦。
- 可以动态的对原有类进行扩展,如何包装取决于调用者,使用灵活。
装饰器模式缺点:
- 装饰器会增加整个调用链的深度,当出现多层的装饰器时整体就会比较复杂。