java设计模式——装饰模式(Decorator Pattern)

       装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。 装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。

定义:装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说, 装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。 根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。

结构:
  • Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
  • ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
  • Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
  • ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

UML图:
java设计模式——装饰模式(Decorator Pattern)_第1张图片

场景:一辆车,可以正常行驶。随着科技不断进步,可以将汽车的功能进一步扩展,现在汽车不但能够行驶,而且能飞,并且还能像船一样在水上面跑。这里的飞行和在水面上跑的两个功能就可以通过装饰模式来实现,下面请看详细代码。

代码分析:
定义一个汽车的抽象类,相当于UML中的 Componet
public abstract class Vehicle {
    //  车辆行驶中
    public abstract void Traveling();
}
具体的component,相当于 ConcreteComponent
public class ConceptCar  extends Vehicle {
    private final String  TAG "ConceptCar";
    @Override
    public void Traveling() {
        Log. d( TAG, " 新概念汽车正在行驶中 ");
    }
}
装饰类
public abstract class Decorator  extends Vehicle{
    private Vehicle  vehicle;
    public Decorator(Vehicle vehicle){
        this. vehicle = vehicle;
    }

    @Override
    public void Traveling() {
        this. vehicle.Traveling();
    }
}
具体的装饰类
public class FlyDecorator  extends Decorator {
    private final String  TAG "FlyDecorator";
    public FlyDecorator(Vehicle vehicle) {
        super(vehicle);
    }

    @Override
    public void Traveling() {
        super.Traveling();
        this.addFlyEquipment();
    }

    /**
     *  修饰方法,给汽车添加飞行装置,让汽车能飞
      */
    private void addFlyEquipment(){
        Log. d( TAG, " 飞行的汽车 ...");
    }
}
具体的装饰类
public class WaterDecorator  extends Decorator {
    private final String  TAG "WaterDecorator";
    public WaterDecorator(Vehicle vehicle) {
        super(vehicle);
    }

    @Override
    public void Traveling() {
        super.Traveling();
        this.addWaterEquipment();
    }
    private void addWaterEquipment(){
        Log. d( TAG" 水上行驶的汽车 ...");
    }
}
客户端:
Vehicle vehicle;
// 获取具体汽车的对象(概念汽车)
vehicle =  new ConceptCar();
// 添加飞行的修饰
vehicle =  new FlyDecorator(vehicle);
// 添加水上行驶的修饰
vehicle =  new WaterDecorator(vehicle);
// 概念车开始行驶了
vehicle.Traveling();

优点:
  • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
  • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
  • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点:
  • 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
  • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

适用环境:
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类: 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类).

扩展:
装饰模式的简化-需要注意的问题:
  • 一个装饰类的接口必须与被装饰类的接口保持相同,对于客户端来说无论是装饰之前的对象还是装饰之后的对象都可以一致对待。
  • 尽量保持具体构件类Component作为一个“轻”类,也就是说不要把太多的逻辑和状态放在具体构件类中,可以通过装饰类 对其进行扩展。如果只有一个具体构件类而没有抽象构件类,那么抽象装饰类可以作为具体构件类的直接子类。


你可能感兴趣的:(设计模式)