1. 程式人生 > >設計模式學習(三): 裝飾者模式 (附C#實現)

設計模式學習(三): 裝飾者模式 (附C#實現)

ring oid decorator 所有 clas blog mage return .cn

需求

做一個咖啡店的訂單系統。

買咖啡時,可以要求加入各種調料,如奶,豆漿,摩卡等。咖啡店會根據調料的不同收取不同的費用。訂單系統要考慮這些。

初版設計

技術分享

然後下面就是所有的咖啡....:

技術分享

cost方法將計算出咖啡加上各種調料後的價格。

這種方法太笨了。。。必須換一種。

再版設計

使用實例變量和繼承!

技術分享

但是有新的問題:

1.調料價格變化就需要更改現有的代碼。

2.一旦出現新的調料,就需要加上新的方法,並改變超類中的cost方法。

3.如果有新的飲料,有些調料可能會不適用。

4.想買雙倍的摩卡咖啡怎麽辦?

設計原則

類應該對擴展開發,對修改關閉。

使用裝飾者模式

技術分享

技術分享

技術分享

裝飾者模式定義

裝飾者模式動態的將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。

技術分享

重新設計

技術分享

C#代碼實現

Beverage:

namespace C03DecoratorPattern.Bases
{
    public abstract class Beverage
    {
        protected string Description;

        protected Beverage()
        {
            Description = "Unknown Beverage";
        }

        public abstract double Cost();

        public virtual
string GetDescription() { return Description; } } }

CondimentDecorator:

namespace C03DecoratorPattern.Bases
{
    public abstract class CondimentDecorator : Beverage
    {
        public abstract override double Cost();
        public abstract override string GetDescription();
    }
}

咖啡們:

namespace C03DecoratorPattern.Beverages
{
    public class Espresso : Beverage
    {
        public Espresso()
        {
            Description = "Espresso";
        }

        public override double Cost()
        {
            return 1.99;
        }
    }
}

namespace C03DecoratorPattern.Beverages
{
    public class HouseBlend : Beverage
    {
        public HouseBlend()
        {
            Description = "House Blend Coffee";
        }

        public override double Cost()
        {
            return .89;
        }
    }
}

調料們:

namespace C03DecoratorPattern.Condiments
{
    public class Milk : CondimentDecorator
    {
        private readonly Beverage _beverage;

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

        public override double Cost()
        {
            return .34 + _beverage.Cost();
        }

        public override string GetDescription()
        {
            return $"{_beverage.GetDescription()}, Milk";
        }
    }
}

namespace C03DecoratorPattern.Condiments
{
    public class Mocha : CondimentDecorator
    {
        private readonly Beverage _beverage;

        public Mocha(Beverage beverage)
        {
            _beverage = beverage;
        }
        public override double Cost()
        {
            return .2 + _beverage.Cost();
        }

        public override string GetDescription()
        {
            return $"{_beverage.GetDescription()}, Mocha";
        }
    }
}

namespace C03DecoratorPattern.Condiments
{
    public class Soy: CondimentDecorator
    {
        private readonly Beverage _beverage;

        public Soy(Beverage beverage)
        {
            _beverage = beverage;
        }

        public override double Cost()
        {
            return .17 + _beverage.Cost();
        }

        public override string GetDescription()
        {
            return $"{_beverage.GetDescription()}, Soy";
        }
    }
}

測試程序:

namespace C03DecoratorPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Beverage beverage = new Espresso();
            Console.WriteLine($"{beverage.GetDescription()} $ {beverage.Cost()}");

            Beverage beverage2 = new HouseBlend();
            beverage2 = new Mocha(beverage2);
            beverage2 = new Milk(beverage2);
            beverage2 = new Soy(beverage2);
            Console.WriteLine($"{beverage2.GetDescription()} $ {beverage2.Cost()}");

            Console.ReadLine();
        }
    }
}

運行結果:

技術分享

設計模式學習(三): 裝飾者模式 (附C#實現)