close

 

No matter when you learned Design Pattern or how you have been already familar with it.

I still highly recommand you to take a look at this tutorial.

The author Christopher Okhravi revealed relevant facts of strategy pattern and I really appreciate the way he`s explained it.

The following is my thoughts after watching that tutorial.

   1: abstract class Duck
   2: {
   3:    readonly IFlyBehavior fb;
   4:    readonly IQuackBehavior qb;
   5:    readonly IDisplayBehavior db;
   6:    protected Duck(IFlyBehavior _fb, IQuackBehavior _qb, IDisplayBehavior _db)
   7:    {
   8:        this.fb = _fb;
   9:        this.qb = _qb;
  10:        this.db = _db;
  11:    }
  12:    public void Fly()
  13:    {
  14:        this.fb.fly();
  15:    }
  16:    public void Display()
  17:    {
  18:        this.db.display();
  19:    }
  20:    public void Quack()
  21:    {
  22:        this.qb.quack();
  23:    }
  24: }

 image

Duck is an abstract class and it is also a super-class of CityDuck, WildDuck and RubberDuck.  

Besides, Duck has three fields(db, fb, and qb), in which they are instances of IFlyBehavior, IQuackBehavior, and IDisplayBehavior

Here, db represents display behavior, fb represents fly behavior, and qb means quack behavior. 

CityDuck, WildDuck and RubberDuck are Duck`s children(sub-classes), so all of them can behave like Duck class does.

We will talk this last and let us get started with three interfaces (IFlyBehavior, IQuackBehavior, and IDisplayBehavior) first.

 

IFlyBehavior

image

From above figure, it is obvious that IFlyBehavior has three children, or say sub-classes, including NoFly, JetFly and SimpleFly.

All of them are similar to each other, that is the reason why we should extract the same behavior to a super-class(IFlyBehavior),

which just contains a method called fly().

NoFly, JetFly and SimpleFly all need to implement fly() in their own ways.

In fact, all kinds of fly() methods provide some flexiblity to meet the changeable requirements in the future.

And such that we may have chance to reuse these derived sub-classes or create a new one derived from it.

   1: interface IFlyBehavior
   2: {
   3:     void fly();
   4: }

 

JetFly:

   1: class JetFly : IFlyBehavior
   2: {
   3:     public void fly()
   4:     {
   5:         Console.WriteLine("I am good at flying.");
   6:         //throw new NotImplementedException();
   7:     }
   8: }

SimpleFly:

   1: class SimpleFly : IFlyBehavior
   2: {
   3:     public void fly()
   4:     {
   5:         Console.WriteLine("I can do simple fly.");
   6:         //throw new NotImplementedException();
   7:     }
   8: }

NoFly:

   1: class NoFly:IFlyBehavior
   2:  {
   3:      public void fly()
   4:      {
   5:          Console.WriteLine("Sorry, I can't fly.");
   6:      }
   7:  }

IQuackBehavior

   1: interface IQuackBehavior
   2: {
   3:    void quack();
   4: }

Like IFlyBehavior, IQuackBehavior plays a role of making sound of quack.

Since NoQuack and SimpleQuack both have IQuackBehavior, they are able to quack().

Besides NoQuack and SimpleQuack have to implement the interface of quack().

Multiple kinds of quack() provide some flexiblity to meet the changeable requirements in the future.

image

NoQuack:

   1: class NoQuack : IQuackBehavior
   2: {
   3:     public void quack()
   4:     {
   5:         Console.WriteLine("Sorry, I can't quack.");
   6:          //throw new NotImplementedException();
   7:     }
   8: }

SimpleQuack:

   1: class SimpleQuack : IQuackBehavior
   2: {
   3:     public void quack()
   4:     {
   5:         Console.WriteLine("I can quack a little bit.");
   6:         //throw new NotImplementedException();
   7:     }
   8: }

IDisplayBehavior

image

Finally, IDisplayBehavior is reponsible for showing something in the form of Graphics or Text by using display() method.

Since DisplayAsGraphics and DisplayAsText both had IDisplayBehavior, they are able to display() something.

Besides, DisplayAsGraphics and DisplayAsText must implement the interface of display().

Multiple kinds of display() provide some flexiblity to meet the changeable requirements in the future.

   1: interface IDisplayBehavior
   2: {
   3:    void display();
   4: }

DisplayAsGraphics:

   1: class DisplayAsGraphics : IDisplayBehavior
   2: {
   3:     public void display()
   4:     {
   5:         Console.WriteLine("This is a DisplayAsGraphics");
   6:         Console.WriteLine("-----------------");
   7:         //throw new NotImplementedException();
   8:     }
   9: }

DisplayAsText:

   1: class DisplayAsText : IDisplayBehavior
   2: {
   3:     public void display()
   4:     {
   5:         Console.WriteLine("This is a DisplayAsText");
   6:         Console.WriteLine("-----------------");
   7:         //throw new NotImplementedException();
   8:     }
   9: }

Duck class

Now back to Duck abstract class, its constructor (Line 6) has three input arguements in order to meet the requirements of the derived class.

   1: abstract class Duck
   2: {
   3:    readonly IFlyBehavior fb;
   4:    readonly IQuackBehavior qb;
   5:    readonly IDisplayBehavior db;
   6:    protected Duck(IFlyBehavior _fb, IQuackBehavior _qb, IDisplayBehavior _db)
   7:    {
   8:        this.fb = _fb;
   9:        this.qb = _qb;
  10:        this.db = _db;
  11:    }
  12:    public void Fly()
  13:    {
  14:        this.fb.fly();
  15:    }
  16:    public void Display()
  17:    {
  18:        this.db.display();
  19:    }
  20:    public void Quack()
  21:    {
  22:        this.qb.quack();
  23:    }
  24: }

To take _fb for example, we are able to input any instance of NoFly, JetFly and SimpleFly.

Following _qb, we are able to input any instance of NoQuack and SimpleQuack.

For _db, we are able to input any instance of DisplayAsGraphics and DisplayAsText.

In other words:

For Fly() method, it is dynamically accomplished with fb.fly(), where fb is associated with the input instance that you choose (NoFly, JetFly or SimpleFly)

For Display() method, it is accomplished with db.display(), where db is associated with the input instance that you choose (DisplayAsGraphics or DisplayAsText)

For Quack() method, it is accomplished with qb.quack(), where qb is associated with the input instance that you choose (NoQuack or SimpleQuack..)

Now we are ready to talk about CityDuck, WildDuck and RubberDuck, all of them are Duck`s children(sub-classes).

CityDuck: If we wish its instance being able to has capability of SimpleFly(), SimpleQuack(), and DisplayAsText().

image

We should pick up suitable sub-class intances to meet the requirements of CityDuck.

The base class(Duck class) is constructed with the following three items

  1. new SimplyFly() object is passed to _fb of super-class(Duck).
  2. new SimplyQuack() object is passed to _qb of super-class(Duck).
  3. new DisplayAsText() object is passed to _db of super-class(Duck).

   1: class CityDuck : Duck
   2: {
   3:     public CityDuck():base(new SimpleFly(), new SimpleQuack(), new DisplayAsText())
   4:     {
   5:  
   6:     }
   7: }

WildDuck: If we wish its instance being able to has capability of JetFly(), SimpleQuack(), and DisplayAsGraphics().

image

We should choose suitable sub-class intances to meet the requirements of WildDuck.

The base class is initialized with the following three items

  1. new JetFly() object is passed to _fb of super-class(Duck).
  2. new SimplyQuack() object is passed to _qb of super-class(Duck).
  3. new DisplayAsGraphics() object is passed to _db of super-class(Duck).
   1: class WildDuck : Duck
   2: {
   3:     public WildDuck() : base(new JetFly(), new SimpleQuack(), new DisplayAsGraphics())
   4:     {
   5:     }
   6: }

RubberDuck: If we wish its instance being able to has capability of NoFly(), NoQuack(), and DisplayAsText().

image

We should choose suitable sub-class intances to meet the requirements of RubberDuck.

The base class is initialized with the following three items

  1. new NoFly() object is passed to _fb of super-class(Duck).
  2. new NoQuack() object is passed to _qb of super-class(Duck).
  3. new DisplayAsText() object is passed to _db of super-class(Duck).
   1: class RubberDuck:Duck
   2: {
   3:    public RubberDuck():base(new NoFly(), new NoQuack(), new DisplayAsText())
   4:    {
   5:  
   6:    }
   7: }

Finally, we are ready to create three kinds of Ducks (rubberDuck, cityDuck, and wildDuck).

Polymorphism techniques are used from line 3 to line 5.

They all perform Quack(), Fly(), and Display() methods, like this:

    • rubberDuck.Quack(); rubberDuck.Fly(); rubberDuck.Display();

    • cityDuck.Quack(); cityDuck.Fly(); cityDuck.Display();

    • wildDuck.Quack(); wildDuck.Fly(); wildDuck.Display();

       

      All methods with same name can help users to call them much more easily.

      Though names of the methods are the same, strtegies inside are not necessarily the same.

      This is one of significant features of strategy pattern.

         1: static void Main(string[] args)
         2: {
         3:     Duck rubberDuck = new RubberDuck();
         4:     Duck cityDuck = new CityDuck();
         5:     Duck wildDuck = new WildDuck();
         6:  
         7:     Console.WriteLine("rubberDuck:");
         8:     rubberDuck.Quack(); rubberDuck.Fly(); rubberDuck.Display();
         9:  
        10:     Console.WriteLine("cityDuck:");
        11:     cityDuck.Quack(); cityDuck.Fly(); cityDuck.Display();
        12:  
        13:     Console.WriteLine("wildDuck:");
        14:     wildDuck.Quack(); wildDuck.Fly(); wildDuck.Display();
        15:  
        16:     Console.ReadKey(); 
        17: }

       

       

      References:

      1. Strategy Pattern – Design Patterns (ep 1) by Christopher Okhravi

      2. Strategy Design Pattern by Derek Banas

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

        天天向上

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