【问题标题】:Fine-grained decorator pattern细粒度装饰器模式
【发布时间】:2011-01-06 11:05:23
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: design-patterns decorator side-effects


    【解决方案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。

    【讨论】:

    • 除了名字我对CQS不熟悉——我在什么方面违反它?
    • 我并不是说您违反了 CQS,但不需要的副作用通常是指向该方向的标志。使用 CQS,方法要么没有副作用,要么只有 副作用。然而,在后一种情况下,副作用永远不会发生。
    【解决方案2】:

    听起来模板最适合您的场景。我不会在不需要时强制组合......this conversation 说得最好,“......这条规则的例外情况:当你应该使用继承时,即如果你需要对可替换性建模。”

    【讨论】:

    • 同意给定的场景听起来很像模板模式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 1970-01-01
    • 2016-05-23
    • 2018-04-10
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多