在Decorator模式中使用抽象Decorator类

Mar*_*rko 6 c# design-patterns

在Decorator设计模式中,我们有一个ItemClass(pe Coffee),然后是一个AbstractDecorator(pe CoffeeDecorator),它包含对Coffee和ConcreteDecorators(如milk)的引用.我的问题是,为什么我们需要AbstractDecorator类,为什么Concrete Decorators不直接从Coffee类继承?或者,如果我们已经想要确保ConcreteDecorators具有对ItemClass的引用,为什么我们没有包含ItemClass属性的接口?使用这个AbstractDecorator我们只是禁用了我们的ConcreteDecorators继承其他类的选项.提前致谢!

Ser*_*kiy 1

我们使用抽象类来删除具体类中的重复项。在装饰器模式中,您需要重复存储装饰对象实例并向其传递调用。如果您不将此逻辑移至基础(抽象)装饰器,那么您将需要在每个具体装饰器中实现此逻辑。


考虑以下饮料界面:

public interface IBeverage
{
    decimal Price { get; }
    string Description { get; }
}
Run Code Online (Sandbox Code Playgroud)

这是由咖啡实现的:

public class Coffee : IBeverage
{
    public decimal Price
    {
        get { return 3.5M; }
    }

    public string Description
    {
        get { return "Coffee"; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您想要创建第一个咖啡装饰器。此时您不需要创建抽象装饰器。让我们的奶蜂免费。只需编写您需要的最简单的代码:

public class Milk : IBeverage
{
    private readonly IBeverage _beverage;

    public Milk(IBeverage beverage)
    {
        _beverage = beverage;
    }

    public decimal Price
    {
        get { return _beverage.Price; } // price not changed
    }

    public string Description
    {
        get { return _beverage.Description + " with milk"; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你需要另一个装饰器。让它成为奶油:

public class Cream : IBeverage
{
    private readonly IBeverage _beverage;

    public Cream(IBeverage beverage)
    {
        _beverage = beverage;
    }

    public decimal Price
    {
        get { return _beverage.Price + 2M; }
    }

    public string Description
    {
        get { return _beverage.Description + " with cream"; }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以看到重复的代码。所以,是时候重构了。让我们将重复的代码移至基本抽象装饰器类,该类的职责将保存对装饰饮料的引用并将调用传递给它:

public abstract class BeverageDecorator : IBeverage
{
    private readonly IBeverage _beverage;

    public BeverageDecorator(IBeverage beverage)
    {
        _beverage = beverage;
    }

    public virtual decimal Price
    {
        get { return _beverage.Price; }
    }

    public virtual string Description
    {
        get { return _beverage.Description; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您只能覆盖那些由装饰器更改行为的调用。牛奶装饰器看起来像:

public class Milk : BeverageDecorator
{
    public Milk(IBeverage beverage)
        : base(beverage)
    {
    }

    public override string Description
    {
        get
        {
            return base.Description + " with milk";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

干净多了,是吗?这就是我们使用基础装饰器的原因。