crazyandcoder

设计模式教程(6-装饰模式)

2021.07.06

装饰模式.png

1 定义

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

2 UML 类图

装饰器模式.gif

在装饰器模式中的角色有:
• 抽象构件 (Component) 角色:给出一个抽象接口,已规范准备接收附加责任的对象。
• 具体构件 (ConcreteComponent) 角色:定义一个将要接收附加责任的类
• 装饰 (Decorator) 角色:持有一个构件 (Component) 对象的实例,并定义一个与抽象构件接口一致的接口。
• 具体装饰 (ConcreteDecorator) 角色:负责给构件对象“贴上”附加的责任。

3 代码实现

3.1 抽象构件 (Component)

public interface Component {
    public void sampleOperation();
}

3.2 具体构件 (ConcreteComponent)

public class ConcreteComponent implements Component{
    @Override
    public void sampleOperation() {
        System.out.println("ConcreteComponent sampleOperation");
    }
}

3.3 装饰 (Decorator)

public class Decorator implements Component{

    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void sampleOperation() {
        //委派给构件
        component.sampleOperation();
        System.out.println("Decorator sampleOperation ");
    }
}

3.4 具体装饰A (ConcreteDecoratorA)

public class ConcreteDecoratorA extends Decorator{

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void sampleOperation() {
        super.sampleOperation();
        System.out.println("ConcreteDecoratorA  sampleOperation");
    }
}

3.5 具体装饰B (ConcreteDecoratorB)

public class ConcreteDecoratorB extends Decorator{

    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void sampleOperation() {
        super.sampleOperation();
        System.out.println("ConcreteDecoratorB  sampleOperation");
    }
}

3.6 Test

public class Client {
    public static void main(String[] args) {

        Component component=new ConcreteComponent();
        Component concreteDecoratorA = new ConcreteDecoratorA(component);
        concreteDecoratorA.sampleOperation();

        System.out.println("***********************");

        Component concreteDecoratorB = new ConcreteDecoratorB(component);
        concreteDecoratorB.sampleOperation();

    }
}

3.7 结果打印

ConcreteComponent sampleOperation
Decorator sampleOperation 
ConcreteDecoratorA  sampleOperation
***********************
ConcreteComponent sampleOperation
Decorator sampleOperation 
ConcreteDecoratorB  sampleOperation

4 优缺点

4.1 优点

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

4.2 缺点

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