23种设计模式之7.装饰器模式

153 阅读2分钟

装饰器模式能够在不改变现有的类的情况下对现有的类进行包装,装饰器类与被装饰类可以完全解耦,摆脱相互依赖。对现有的类进行功能动态的增加。

下面在代码中使用装饰器模式完成一个小功能,理解一下装饰器模式思想。

假设有一个可拍照的接口,实现该接口的事物都可以拍照:

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();
    }
}

运行结果如下图:

image.png

值得注意的是装饰的顺序与代码的顺序是相反的,这点通过分析代码就可以得出,也可以想象为包粽子,最后包的粽叶肯定是最外的,也就是最先看到的嘛。

装饰器模式优点:

  1. 不改变原有类的基础上对原有类进行增强,装饰类与原有类完全解耦。
  2. 可以动态的对原有类进行扩展,如何包装取决于调用者,使用灵活。

装饰器模式缺点:

  1. 装饰器会增加整个调用链的深度,当出现多层的装饰器时整体就会比较复杂。