具有复合设计模式的装饰器设计模式

Decorator design pattern with Composite Design pattern

我了解复合设计模式和装饰器设计模式及其用途。我们可以有一个我们必须一起使用它们的情况吗?这种情况下的 class 图会是什么样子?

我们是否会从组件继承装饰器(来自装饰器设计模式)、叶节点和复合材料(来自复合设计模式)? 这是我指的装饰器模式:wiki link for decorator pattern 对于复合模式:composite wiki link

装饰器在装饰单个对象的同时委托其方法并因此修改其行为。考虑具有单个方法 String asString(); 的接口 Text 一个示例 class,例如 TrimmedTextUpperCaseTextLowerCaseText

复合体是零到 n 个对象的容器,仅将行为委托给其子对象。

然而,这些可以组合成一个叫做 复合装饰器 的东西,相对于前面的示例,这将是 ConcatenatedText

下面是一些代码,证明复合 class 也可以充当装饰器并自己被装饰:

interface Text {
    String asString();

    // just a static helper to construct an instance of Text quickly
    static Text of(String text) {
        return () -> text;
    }
}
// 1st decorator
@AllArgsConstructor
static class TrimmedText implements Text {
    Text text;

    @Override
    public String asString() {
        return text.asString().trim();
    }
}

// 2nd decorator
@AllArgsConstructor
static class UpperCaseText implements Text {
    Text text;

    @Override
    public String asString() {
        return text.asString().toUpperCase();
    }
}
// composite decorator
@AllArgsConstructor
static class ConcatenatedText implements Text {
    List<Text> texts;

    public void add(String text) {
        texts.add(Text.of(text));
    }

    @Override
    public String asString() {
        return texts.stream().map(Text::asString).collect(Collectors.joining(", "));
    }
}
@Test
void foo() {
    Text trimmedUpperCaseText = new TrimmedText(new UpperCaseText(Text.of(" a b c ")));
    assertThat(trimmedUpperCaseText.asString(), is("A B C"));

    ConcatenatedText concatenatedText = new ConcatenatedText(new ArrayList<>(List.of(
        new UpperCaseText(Text.of("    a    ")),
        new TrimmedText(Text.of("    b    ")))));

    concatenatedText.add("c");

    Text refinedText = new TrimmedText(concatenatedText);

    assertThat(refinedText.asString(), is("A    , b, c")
}

是的,decorator pattern is often used together with a composite pattern. Here is what GoF 说:

Decorator is often used with Composite. When decorators and composites are used together, they will usually have a common parent class. So decorators will have to support the Component interface (...)

原因是复合模式的目标是让:

clients treat individual objects and compositions of objects uniformely.

将两者结合起来可以使用装饰器向复合材料和叶子添加功能和职责,因此使用 composition over inheritance。主要好处是:

  • 避免不太灵活继承的缺点
  • 避免重复实现通用接口的弊端
  • 如果目标是添加共同职责,则允许对组合和叶子重用相同的装饰器

结果如下:

有趣的是,装饰器模式在图形上看起来与复合模式相似,这可能让人感到不安。 GoF解释了这种感觉:

A decorator can be viewed as a degenerate composite with only one component. However a decorator adds additional responsibilities (...)