装饰器模式简介

概念

装饰器模式(Decorator Pattern)是一种结构型设计模式,允许您在不改变现有对象结构的情况下,动态地将新功能附加到对象上。通过创建一个包装器类来扩展原始类的功能。这个包装器类具有与原始类相同的接口,并在内部持有一个指向原始对象的引用。通过将多个包装器链接在一起,可以递归地添加任意数量的功能。

特点

  1. 装饰器和被装饰对象实现相同接口,使得客户端无需关心具体类型。
  2. 可以动态地添加、删除或组合多个装饰器。
  3. 不需要修改已存在代码即可扩展功能。

优点

  1. 提供了灵活性和可扩展性,可以根据需要逐步增加或移除功能。
  2. 遵循开闭原则,不需要修改现有代码即可实现新功能。
  3. 具备了继承关系所缺乏的灵活性。

缺点

  1. 增加了系统中类的数量,在某些情况下可能会增加复杂度和理解难度。
  2. 如果使用不当,可能会导致过多嵌套或产生大量小粒度对象。

适用场景

  1. 当希望为一个对象动态地添加额外的功能时,可以使用装饰器模式。
  2. 当不适合使用继承来扩展对象功能时,可以考虑使用该模式。

实现方式

使用抽象类作为基础组件

实现原理:

  1. 定义一个抽象类,该抽象类定义了需要被包装和扩展功能的方法。
  2. 创建一个抽象装饰器类,它继承自该抽象类。这个抽象装饰器持有一个指向基础组件对象(即被包装对象)的引用。
  3. 在具体子类中,通过调用父级构造函数传入被包装对象,并重写相关方法,在其中添加额外功能并调用父级方法以保留原始行为。

实现代码:

java 复制代码
// 抽象基础组件
abstract class Component {
    public abstract void operation();
}

// 具体基础组件
class ConcreteComponent extends Component {
    public void operation() {
        System.out.println("执行具体操作");
    }
}

// 抽象装饰器
abstract class Decorator extends Component {
    protected Component component;

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

    public void operation() {
        if (component != null) {
            component.operation();
        }
    }
}

// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    public void addedBehavior() {
        System.out.println("新增附加行为 A");
    }

    public void operation(){
        super.operation();
        addedBehavior();
    }
}

// 具体装饰器B
class ConcreteDecoratorB extends Decorator{
    public ConcreteDecoratorB(Component comp){
        super(comp);
    }

    public void addedBehavior(){
        System.out.println("新增附加行为 B");
    }

    public void operation(){
        super.operation();
        addedBehavior();
    }
}
// 使用示例
public class Main {
    public static void main(String[] args) {
// 使用示例
        Component component = new ConcreteComponent();
        component = new ConcreteDecoratorA(component);
        component.operation();
        component = new ConcreteDecoratorB(component);
        component.operation();
    }
}

在上述示例中,我们定义了一个抽象基础组件类Component,它包含一个抽象方法operation()。然后创建了具体的基础组件类ConcreteComponent,它实现了这个抽象方法。

接下来,我们创建了一个抽象装饰器类Decorator,它也继承自基础组件类,并持有一个指向基础组件对象的引用。在装饰器类中,我们通过调用基础组件对象的operation()方法来实现具体功能。

然后,我们创建了两个具体装饰器类ConcreteDecoratorA和ConcreteDecoratorB,它们分别扩展了抽象装饰器类并添加了额外的功能。在这些具体装饰器中,我们首先调用父类的operation()方法来执行原始操作,然后再执行附加行为。

最后,在客户端代码中,我们创建一个具体基础组件对象,并使用多个具体装饰器对象进行包裹和扩展。通过调用最外层装饰器对象的operation()方法来触发整个装饰过程上所有操作的执行。

需要注意,在这种方式下,每次增加新类型或结构变化时都需要修改相关子类。这可能会导致代码的脆弱性。

使用接口作为基础组件

实现原理:

  1. 定义一个接口作为基础组件,该接口定义了需要被装饰的方法。
  2. 创建一个具体的基础组件类来实现该接口,并实现具体的业务逻辑。
  3. 创建一个抽象装饰器类,它也实现了相同的接口。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。
  4. 创建具体装饰器类来扩展功能。这些具体装饰器也是通过实现抽象装饰器并添加额外功能来实现。

实现代码:

java 复制代码
// 基础组件
interface Component {
    void operation();
}

// 具体基础组件
class ConcreteComponent implements Component {
    public void operation() {
        System.out.println("执行具体操作");
    }
}

// 抽象装饰器
abstract class Decorator implements Component {
    protected Component component;

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

    public void operation() {
        if (component != null) {
            component.operation();
        }
    }
}

// 具体装饰器A
class ConcreteDecoratorA implements Component {
    private Component component;

    public ConcreteDecoratorA(Component comp){
        this.component = comp;
    }

    public void addedBehavior(){
        System.out.println("新增附加行为 A");
    }

    public void operation(){
        if(component != null){
            component.operation();
        }
        addedBehavior();
    }
}

// 具体装饰器B
class ConcreteDecoratorB implements Component {
    private Component component;

    public ConcreteDecoratorB(Component comp){
        this.component = comp;
    }

    public void addedBehavior(){
        System.out.println("新增附加行为 B");
    }

    public void operation(){
        if(component != null){
            component.operation();
        }
        addedBehavior();
    }
}


public class Main {
    public static void main(String[] args) {
        // 使用示例
        Component component = new ConcreteComponent();
        component = new ConcreteDecoratorA(component);
        component = new ConcreteDecoratorB(component);
        component.operation();
    }
}

在上述示例中,我们定义了一个基础组件接口Component,它包含一个方法operation()。

然后创建了具体的基础组件类ConcreteComponent,它实现了该接口并实现具体的业务逻辑。

接下来,我们创建了抽象装饰器类 Decorator ,它也实现了相同的接口。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。

然后,我们创建了两个具体装饰器类 ConcreteDecoratorA 和 ConcreteDecoratorB ,它们分别实现了该接口并扩展了功能。在这些具体装饰器中,我们首先调用基础组件对象的 operation() 方法来执行原始操作,然后再执行附加行为。

最后,在客户端代码中,我们创建一个具体基础组件对象,并使用多个具体装饰器对象进行包裹和扩展。通过调用最外层装饰器对象的 operation() 方法来触发整个装饰过程上所有操作的执行。

存在的问题:

  1. 需要在每个具体装饰器中重新声明所有方法,即使它们只是简单地委派给基础组件对象。
  2. 如果需要改变已有代码结构(例如新增一种新类型),则需要修改所有相关子类。

动态装饰器链

实现原理:

  1. 定义一个接口或抽象类作为基础组件,该接口或类定义了需要被装饰的方法。
  2. 创建具体的基础组件类来实现该接口或继承该抽象类,并实现具体的业务逻辑。
  3. 创建一个抽象装饰器类,它也实现了相同的接口或继承相同的抽象类。这个装饰器持有一个指向基础组件对象的引用,并在其内部调用基础组件对象对应方法。
  4. 在抽象装饰器中添加一个方法,用于动态地添加下一个具体装饰器到链中。
  5. 创建具体装饰器类来扩展功能。这些具体装饰器也是通过继承抽象装饰器并添加额外功能来实现。

实现代码:

java 复制代码
// 基础组件
interface Component {
    void operation();
}

// 具体基础组件
class ConcreteComponent implements Component {
    public void operation() {
        System.out.println("执行具体操作");
    }
}

// 抽象装饰器
abstract class Decorator implements Component {
    protected Component component;
    protected Decorator nextDecorator;

    public void setNextDecorator(Decorator decorator) {
        this.nextDecorator = decorator;
    }

    public void operation() {
        if (component != null) {
            component.operation();
        }

        if (nextDecorator != null) {
            nextDecorator.operation();
        }
    }
}

// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component comp){
        this.component = comp;
    }

    public void addedBehavior(){
        System.out.println("新增附加行为 A");
    }

    public void operation(){
        if(component != null){
            component.operation();
        }

        addedBehavior();

        if(nextDecorator != null){
            nextDecorator.operation();
        }
    }
}

// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component comp){
        this.component = comp;
    }

    public void addedBehavior(){
        System.out.println("新增附加行为 B");
    }

    public void operation(){
        if(component != null){
            component.operation();
        }
        addedBehavior();

        if(nextDecorator!=null){
            nextDecorator.operation();
        }
    }
}



public class Main {
    public static void main(String[] args) {
        // 使用示例
        Component component = new ConcreteComponent();

        ConcreteDecoratorA decoratorA = new ConcreteDecoratorA(component);
        ConcreteDecoratorB decoratorB = new ConcreteDecoratorB(component);
        decoratorA.setNextDecorator(decoratorB);

        decoratorA.operation();
    }
}

存在问题
使用动态装饰器链时可能会遇到以下问题:

  1. 链中每个节点都需要知道下一个节点,增加了耦合性和复杂性。
  2. 动态修改链可能会导致不可预测行为和难以调试。
相关推荐
许野平21 分钟前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
也无晴也无风雨24 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
狂奔solar33 分钟前
yelp数据集上识别潜在的热门商家
开发语言·python
duration~36 分钟前
Maven随笔
java·maven
zmgst39 分钟前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
何曾参静谧1 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
暗黑起源喵1 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong2 小时前
Java反射
java·开发语言·反射