6

Decorator デザイン パターンには、ItemClass (pe Coffee)、Coffee への参照を含む AbstractDecorator (pe CoffeeDecorator)、および ConcreteDecorators (ミルクなど) があります。私の質問は、なぜ AbstractDecorator クラスが必要なのか、なぜ Concrete Decorators が Coffee クラスから直接継承しないのかということです。あるいは、ConcreteDecorators が ItemClass への参照を持つようにしたいのであれば、なぜ ItemClass プロパティを含むインターフェースを持たないのでしょうか? この AbstractDecorator を使用して、ConcreteDecorators が他のクラスを継承するオプションを無効にしているだけです。前もって感謝します!

4

1 に答える 1

1

抽象クラスを使用して、具体的なクラスから重複を取り除きます。デコレータ パターンでは、装飾されたオブジェクト インスタンスの格納と呼び出しの受け渡しが重複しています。このロジックをベース (抽象) デコレーターに移動しない場合は、すべての具象デコレーターでこれを実装する必要があります。


次の飲料インターフェイスを検討してください。

public interface IBeverage
{
    decimal Price { get; }
    string Description { get; }
}

これはコーヒーによって実装されています:

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

    public string Description
    {
        get { return "Coffee"; }
    }
}

次に、コーヒー用の最初のデコレータを作成します。現時点では抽象デコレータを作成する必要はありません。私たちのミルクビーを無料でどうぞ。必要な最も単純なコードを書くだけです。

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"; }
    }
}

ここで、別のデコレータが必要です。クリームにしましょう:

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"; }
    }
}

重複したコードが表示されます。それでは、リファクタリングの時間です。複製されたコードをベースの抽象デコレータ クラスに移動しましょう。この責任は、装飾された飲料への参照を保持し、呼び出しを渡します。

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; }
    }
}

これで、デコレーターによって動作が変更された呼び出しのみをオーバーライドできるようになりました。ミルク デコレータは次のようになります。

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

    public override string Description
    {
        get
        {
            return base.Description + " with milk";
        }
    }
}

ずっときれいですよね?そのため、base デコレーターを使用します。

于 2013-10-18T10:09:06.787 に答える