细粒度装饰器模式

3
我理解装饰器模式的最简单形式,其想法是一个类包装另一个类,在调用装饰对象上的同一方法之前和/或之后运行一些其他代码。
然而,我遇到了这样的情况:不能简单地调用已装饰方法,因为它具有一些不希望出现的副作用。但是,我确实希望大部分装饰方法能够运行。
因此,我认为需要将装饰方法拆分成多个方法,然后在装饰器中可以调用其中一些方法,运行我的修饰代码,然后调用其他一些方法——省略我不想要的副作用。
但是为了保持多态性,这意味着必须将这些方法添加到装饰和被装饰对象实现的接口中。这是不可取的;它们不应该是公共的,而且它有效地意味着装饰的类知道它将如何被装饰。
我认为模板模式可能更合适,一个抽象基类依次调用每个较小的方法,在“装饰器”只需提供所关心的方法的替代实现。但这并不完全符合“组合优于继承”的原则,那你有什么建议?
2个回答

2

听起来模板最适合你的情况。如果不需要强制组合,我就不会强制推荐 ...这个对话说得最好,"...这个规则有例外:当你需要建模的是可替代性的时候,你应该使用继承。"


同意所提供的场景听起来非常像模板模式。 - Vincent Ramdhanie

1

听起来你的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。

1
我对CQS不熟悉,除了名字之外 - 我违反了哪些方面? - Neil Barnwell
我并不是说你违反了CQS,但是不必要的副作用通常是指向这个方向的信号。在CQS中,方法要么没有副作用,要么只有副作用。然而,在后一种情况下,副作用从来都不是不需要的。 - Mark Seemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接