细粒度的装饰图案

时间:2010-01-18 17:05:28

标签: design-patterns decorator side-effects

我理解Decorator模式,用最简单的术语来说。这个想法是一个类包装另一个类,其中装饰器方法希望在装饰对象上调用相同方法之前和/或之后运行一些其他代码。

然而,我遇到了一个我不能简单地调用装饰方法的情况,因为它有一些不受欢迎的副作用。但是我想要运行这个装饰方法的大部分。

所以我相信我需要将装饰方法拆分为多个方法,然后在装饰器中我可以调用其中的一些,运行我的装饰代码,然后调用其他方法 - 错过了我不想要的副作用

但是,为了保持多态性,这意味着将这些方法添加到装饰和装饰器对象实现的接口。这是不可取的;它们不应该是公开的,它实际上意味着装饰的阶级知道它将如何装饰。

我认为模板模式可能更合适,抽象基类依次调用每个较小的方法,其中“装饰器”只为它关心的那些提供替代实现。然而,这并不完全是“构图而非继承”,所以你推荐什么?

2 个答案:

答案 0 :(得分:2)

听起来像模板最适合你的场景。在不需要的时候我不会强迫组合...... this conversation说得最好,“......这个规则的例外:你应该使用继承,即如果你需要模拟可替代性。”

答案 1 :(得分:1)

听起来您的API违反了Command-Query Separation,因此您最好的选择是重新设计API。

但是,如果我错了或重新设计是不可能的,也许您可​​以将装饰类的方法拆分为两种方法,而无需更改界面。

public interface IMyInterface
{
    Foo GetFoo(Bar bar);
}

public class MyClass : IMyInterface
{
    public Foo GetFoo(Bar bar)
    {
        this.DoSomethingWithSideEffects(bar);
        return this.DoSomethingToGetFoo(bar);
    }

    public Foo DoSomethingToGetFoo(Bar bar)
    {
        // ...
    }

    public void DoSomethingWithSideEffects(Bar bar)
    {
        // ...
    }
}

public class MyDecorator : IMyInterface
{
    private readonly MyClass mc;

    public MyDecorator(MyClass mc)
    {
        // put Null Guard here...
        this.mc = mc;
    }

    public Foo GetFoo(Bar bar)
    {
        return this.mc.DoSomethingToGetFoo(bar);
    }
}

请注意,MyDecorator会修饰MyClass而不是IMyInterface。