close

 

Today, I am going to organize something about decorator pattern, which is my thoghts after watching the tutorial created by Christopher Okhravi.
Besides I would like to implement it by using C# and hope that would help someone who is also learning decorator pattern.

 

image

Decaf and Espresso are sub-classes of BeverageBase, so both of them inherit two public abstract methods: getDesc() and Cost().

BeverageBase portion:

   1: public abstract class BeverageBase
   2: {
   3:     public abstract string getDesc();
   4:     public abstract int Cost();
   5: }

Decaf portion:

   1: public class Decaf : BeverageBase
   2: {
   3:    public override int Cost()
   4:    {
   5:        return 2;
   6:    }
   7:  
   8:    public override string getDesc()
   9:    {
  10:        Console.WriteLine("2. Decaf");
  11:        return "Decaf";
  12:    }
  13: }

Espresso portion:

   1: public class Espresso:BeverageBase
   2: {
   3:    public override int Cost()
   4:    {
   5:        return 1;
   6:    }
   7:    public override string getDesc()
   8:    {
   9:        Console.WriteLine("1. Espresso");
  10:        return "Espresso";
  11:    }
  12: }

 

Now the problem is if we want to add something to Decaf or Espresso, how would you do that?
Intuitively, you may create another class named AddonDecorator, which also inherits BeverageBase class.
But the combination of addons are changeable, for example:
1. espresso + caramel
「espresso  caramel」的圖片搜尋結果

2. decaf + soymilk

「soymilk」的圖片搜尋結果

3. decaf + soymilk + caramel

相關圖片

4. decaf + soymilk + 2*caramel 

相關圖片

The above example shows four different combinations by using multiple“+”operators, which put all addons together step by step.
Here, caramel and soymilk are two kinds of addons.
Both of them can be viewed as sort of variations of BeverageBase, namely AddonDecorator

 AddonDecorator Portion:

   1: public abstract class AddonDecorator : BeverageBase
   2: {
   3:  
   4: }

 

For example, if we create a new menu of beverage: decaf + soymilk + caramel.
It not only keeps functions of BeverageBase(decaf) but also adds some addtional stuffs, namely AddonDecorators(soymilk + caramel).
Here comes the concept of decorator pattern: if we want to keep something( is_a) and also to add something (has_a).

CaramelDecorator portion:

   1: public class CaramelDecorator : AddonDecorator  // is_a
   2: {
   3:     BeverageBase beverage;  // has_a
   4:  
   5:     public CaramelDecorator(BeverageBase _beverage)
   6:     {
   7:         this.beverage = _beverage;
   8:     }
   9:     public override int Cost()
  10:     {
  11:         return this.beverage.Cost() + 3;
  12:     }
  13:  
  14:     public override string getDesc()
  15:     {
  16:         if (beverage != null)
  17:         {
  18:             beverage.getDesc();
  19:         }
  20:         Console.WriteLine("3. Caramel");
  21:         return "Caramel";
  22:     }
  23: }

SoymilkDecorator Portion:

   1: public class SoymilkDecorator : AddonDecorator  // is_a
   2: {
   3:     BeverageBase beverage;    // has_a
   4:     public SoymilkDecorator(BeverageBase _beverage)
   5:     {
   6:         this.beverage = _beverage;
   7:     }
   8:  
   9:     public override int Cost()
  10:     {
  11:         return this.beverage.Cost() + 4;
  12:     }
  13:  
  14:     public override string getDesc()
  15:     {
  16:         if(beverage!=null)
  17:         {
  18:             beverage.getDesc();
  19:         }
  20:         Console.WriteLine("4. Soymilk");
  21:         return "Soymilk";
  22:     }
  23: }

image

   1: static void Main(string[] args)
   2: {
   3:    BeverageBase decaf = new Decaf();
   4:    BeverageBase espresso = new Espresso();
   5:  
   6:    BeverageBase order1 = new CaramelDecorator(espresso);
   7:    Console.WriteLine("Order1 : espresso + caramel");
   8:    order1.getDesc();
   9:    Console.WriteLine("Pay for order1: {0}\n", order1.Cost()); 
  10:  
  11:    BeverageBase order2 = new SoymilkDecorator(decaf);
  12:    Console.WriteLine("Order2 : decaf + soymilk");
  13:    order2.getDesc();
  14:    Console.WriteLine("Pay for order2: {0}\n", order2.Cost());
  15:  
  16:    BeverageBase order3 = new CaramelDecorator(order2);
  17:    Console.WriteLine("Order3 : decaf + soymilk + caramel");
  18:    order3.getDesc();
  19:    Console.WriteLine("Pay for order3: {0}\n", order3.Cost());
  20:  
  21:    BeverageBase order4 = new CaramelDecorator(order3);
  22:    Console.WriteLine("Order4 : decaf + soymilk + 2*caramel");
  23:    order4.getDesc();
  24:    Console.WriteLine("Pay for order4: {0}\n", order4.Cost());
  25:    Console.ReadKey();
  26:  
  27: }

The following screenshot demonstrates the above four combinations of beverage by using decorator pattern technique.

image

Now let`s review four types of order in another way

1. espresso + caramel

image

2. decaf + soymilk

image

3. decaf + soymilk + caramel

image

4. decaf + soymilk + 2*caramel 

image

 

(1) Decorating Sequence: decorator #1decorator #2→decorator #3 

    • ( SoymilkDecorator decorates Decaf ), which is labeled as decorator #1

    • ( CaramelDecorator decorates decorator #1), which is labeled as decorator #2

    • ( CaramelDecorator decorates decorator #2), which is labeled as decorator #3

      (2) Calling Sequence: decorator #3→decorator #2decorator #1

      (3) Executing Sequence: decorator #1decorator #2→decorator #3 

       

       

      Other usefule articles:

      1. 【C#】裝飾者模式(Decorator Pattern)

      arrow
      arrow
        全站熱搜
        創作者介紹
        創作者 me1237guy 的頭像
        me1237guy

        天天向上

        me1237guy 發表在 痞客邦 留言(0) 人氣()