Design patterns 细粒度装饰图案

Design patterns 细粒度装饰图案,design-patterns,decorator,side-effects,Design Patterns,Decorator,Side Effects,我理解装饰图案,用最简单的术语来说。其思想是一个类包装另一个类,其中装饰器方法希望在对装饰对象调用相同方法之前和/或之后运行其他代码 然而,我遇到了这样的情况,我不能简单地调用修饰方法,因为它有一些不希望的副作用。但是,我确实希望运行大部分装饰过的方法 因此,我认为我需要将修饰的方法拆分为多个方法,然后在decorator中调用其中的一些方法,运行我的修饰代码,然后调用其他一些方法-忽略我不想要的副作用 然而,为了保持多态性,这意味着将这些方法添加到装饰和装饰对象实现的接口中。这是不可取的;他们

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

然而,我遇到了这样的情况,我不能简单地调用修饰方法,因为它有一些不希望的副作用。但是,我确实希望运行大部分装饰过的方法

因此,我认为我需要将修饰的方法拆分为多个方法,然后在decorator中调用其中的一些方法,运行我的修饰代码,然后调用其他一些方法-忽略我不想要的副作用

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


我认为模板模式可能更合适,抽象基类依次调用每个较小的方法,“装饰器”只是为它关心的方法提供一个替代实现。然而,这并不完全是“组合重于继承”,所以您有什么建议吗?

听起来模板最适合您的场景。我不会在不需要的时候强制构图。。。最好的说法是,“…此规则的例外情况:何时应该使用继承,即如果需要建模可替换性。”

听起来您的API违反了此规则,因此您最好的选择是重新设计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。

同意给定的场景听起来很像模板模式。除了名称之外,我对CQS不太熟悉-我以什么方式违反了它?我不是说你违反了CQS,但不想要的副作用通常是指向那个方向的标志。使用CQS,方法要么没有副作用,要么只有副作用。然而,在后一种情况下,副作用从来都不是多余的。