策略模式

不愿透露姓名的小村村發表於2024-09-23

1. 先做一個不那麼恰當的例子

 //1.先做一個Duck class
    public abstract class SimUDuck
    {
        void quack()
        {
            Console.WriteLine("鴨子都會嘎嘎叫");
        }
        void swim()
        {
            Console.WriteLine("鴨子都會游泳");
        }
      public  abstract void display();//每個鴨子型別看起來都不一樣,所以做成抽象方法

        //這樣寫在父類裡面,那麼不能飛的鴨子也繼承了飛的行為,如下寫是不對的:
        //void fly()
        //{
        //    Console.WriteLine("新增的需求:讓某些鴨子能飛");
        //}

        public abstract void fly();//讓子類自己去判斷能不能飛,但是這樣程式碼量會變大,因為每一個繼承它的子類都要複寫一遍這個方法
    }

    class MallardDuck : SimUDuck
    { 
        public override void display() 
        {
            Console.WriteLine("看起來像綠頭鴨");
        }
        public override void fly() 
        {
            Console.WriteLine("綠頭鴨會飛");
        }
    }

    class RedHeadDuck : SimUDuck
    {
        public override void display()
        {
            Console.WriteLine("看起來像紅頭鴨");
        }

        public override void fly()
        {
            Console.WriteLine("紅頭鴨會飛");
        }
    }

    class RubberDuck : SimUDuck
    {
        public override void display()
        {
            Console.WriteLine("看起來像橡皮鴨");
        }

        public override void fly()
        {
            Console.WriteLine("橡皮鴨會飛的方法寫成空,表示橡皮鴨不能飛");//程式碼量會變大,因為每一個繼承它的子類都要複寫一遍這個方法,這樣也是不行的
        }
    }

在上面的例子裡面:

  • 鴨子的叫聲和游泳可能也是變化的,在父類中寫定了是不行的
  • 如果在父類中寫定一個飛的例項方法,子類繼承後,那麼本來不應該會飛的子類也有了會飛的特性了。
  • 如果父類方法全部做成抽象類,每一次子類的繼承就要去重寫一遍父類方法,就算有些鴨子不會飛,那也要重寫為不會飛,這也是很低效的。

2. 用介面和演算法簇實現

//1.先做一個Duck class
    public abstract class SimUDuck
    {
        //宣告介面的引用關聯關係
        public IFlyBehavior flyBehavior;
        public IQuackBehavior quackBehavior;
        public void performFly()//父類不具體實現飛的方法,委託給介面
        {
            flyBehavior.fly();
        }
       public void performQuack() //父類不具體實現叫的方法,委託給介面
        {
            quackBehavior.quack();
        }
        void swim()//所有父類和子類都一致的方法
        {
            Console.WriteLine("鴨子都會游泳");
        }
        public void setFlyBehavior(IFlyBehavior fb)//這兩個方法用來動態實現具體的方法,而不是像原來一樣寫在建構函式里
        {
            flyBehavior = fb;
        }
        public void setQuackBehavior(IQuackBehavior qb)
        {
            quackBehavior = qb;
        }
        public abstract void display();//每個子類的都有的方法,但是每個子類的表現卻不一樣,所以做成抽象方法子類重寫
    }

    class MallardDuck : SimUDuck
    {
        public MallardDuck()
        {
            base.quackBehavior = new Quack();//使用父類的欄位
            base.flyBehavior = new FlyWithWings();
        }
        public override void display()
        {
            Console.WriteLine("看起來像綠頭鴨");
        }
    }

    class RedHeadDuck : SimUDuck
    {
        public override void display()
        {
            Console.WriteLine("看起來像紅頭鴨");
        }
    }

    class RubberDuck : SimUDuck
    {
        public override void display()
        {
            Console.WriteLine("看起來像橡皮鴨");
        }
    }
    class DecoyDuck : SimUDuck
    {
        public override void display()
        {
            Console.WriteLine("看起來像誘餌鴨");
        }
    }
    class FlyWithWings:IFlyBehavior
    {
        public void fly()
        {
            Console.WriteLine("有翅膀可以飛");
        }
    }
    class FlyNoWay : IFlyBehavior
    {
        public void fly()
        {
            Console.WriteLine("沒有翅膀不能飛");
        }
    }
    class Quack: IQuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("嘎嘎叫");
        }
    }
    class Squeack: IQuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("吱吱叫");
        }
    }
    class MuteQuack: IQuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("不會叫");
        }
    }
    public interface IFlyBehavior//把變化的飛行行為做成介面
    {
        void fly();
    }
    public interface IQuackBehavior//把變化的叫聲行為做成介面
    {
        void quack();
    }
  • 實現寫在具體的類裡面
  • 父類關聯具體的介面,實現演算法的具體類關聯介面
  • 介面的方法被具體的類實現
  • 策略模式

相關文章