Strategy 策略模式

Posted blackteeth

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Strategy 策略模式相关的知识,希望对你有一定的参考价值。

策略模式:定义一系列的算法,把他们一个个封装起来,并且使它们可以相互替换,。本模式使得算法可以独立于使用它的客户而变化。

故事背景:开发一款鸭子模拟游戏,游戏中会出现各种鸭子,一边游泳,一边嘎嘎叫。此系统的内部使用了标准的OO技术,设计了一个鸭子基类,并让各种鸭子继承此基类。基类中有Speak()方法,Swim()方法,还有一个虚方法Display()。3个子类WhiteDuck,BlackDuck,RubberDuck

代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace StrategyPattern
 8 {
 9    public  class Duck
10     {
11         protected string name = "duck";
12         public Duck()
13         {
14 
15         }
16         public Duck(string name)
17         {
18             this.name = name;
19         }
20         public void Quack()
21         {
22             Console.WriteLine(name + "鸭子在嘎嘎叫");
23         }
24         public void Swim()
25         {
26             Console.WriteLine(name + "鸭子在游泳");
27         }
28 
29         public virtual void Display()
30         {
31             Console.WriteLine(name + "基类的display方法被调用");
32         }
33         public void Fly()
34         {
35             Console.WriteLine(name + "鸭子在飞");
36         }
37     }
38 }

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace StrategyPattern
 8 {
 9     class RedDuck :Duck
10     {
11         public RedDuck()
12         {
13 
14         }
15         public RedDuck(string name):base(name)
16         {
17 
18         }
19         public override void Display()
20         {
21          
22             Console.WriteLine(name + "红头鸭子");
23         }
24     }
25 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace StrategyPattern
 8 {
 9     class GreenDuck:Duck
10     {
11         public GreenDuck()
12         {
13 
14         }
15         public GreenDuck(string name):base(name)
16         {
17 
18         }
19         public override void Display()
20         {
21             Console.WriteLine(name + "绿头鸭子");
22         }
23     }
24 }
using System;

namespace StrategyPattern
{
    class RubberDuck:Duck
    {
        public RubberDuck()
        {

        }
        public RubberDuck(string name):base(name)
        {
            
        }

        public override void Display()
        {
            Console.WriteLine(name + "橡皮鸭子");
        }

    }
}
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace StrategyPattern
 8 {
 9     class Client
10     {
11         static void Main(string[] args)
12         {
13             Duck redDuck = new RedDuck("Mr.Red");
14             redDuck.Display();
15             redDuck.Quack();
16             redDuck.Swim();
17 
18             Duck greenDuck = new GreenDuck("Mr.Green");
19             greenDuck.Display();
20             greenDuck.Quack();
21             greenDuck.Swim();
22 
23             Duck rubberDuck = new RubberDuck("Mr.Rubber");
24             rubberDuck.Display();
25             rubberDuck.Quack();
26             rubberDuck.Swim();
27 
28             Console.ReadKey();
29         }
30     }
31 }

运行结果:技术分享图片

 

新的需求:现在需要会飞的鸭子

实现:只要在基类中新加一个Fly()方法,然后在客户端调用就可以了。真的是这样么?如果这样做,你会RubberDuck在飞(注:rubber 橡皮),这可不是我们想要的结果。

要想解决这个办法很简单,在RubberDuck中定义一个同名函数隐藏基类中的同名方法Fly,然后什么都不做就行了。或者把Fly设计成一个虚方法,同样在子类中覆盖,什么都不做就行了。

 

新的需求:需要诱饵鸭子,既不会飞,也不会叫。解决这个问题的方法也很简单,在定义一个子类DecoyDuck,覆盖子类的Fly和Speak方法就行了,同样方法体为空。

思考:利用继承来提供Duck的行为导致的缺点:

1.运行时的行为不容易改变

2.改变会牵一发而动全身,造成其他鸭子不想要的改变。

3.代码在多个子类中重复

4.很难直到所有鸭子的全部行为。

策略模式大显身手:

把行为与Duck分离出来,定义两个接口QuackBehaviour和FlyBehaviour。定义两个实现QuackBehaviour的类:QuackLoudly和QuackMute。定义两个实现FlyB ehaviour的类:FlyWithWings和FlyNoway。

Duck中删除Fly和Quack方法,添加PerformQuack和PerformFly方法。要想获得叫和飞的行为只要获得飞和叫的类就可以了,让飞和叫的类取实现这些功能。因此需要在Duck中添加两个接口的引用:

QuackBehaviour quackBehaviour 和 FlyBehaviour flyBehaviour。获得引用还不行,还需要获得实例。因此再添加2个方法:SetQuackBehaviour(QuackBehaviour qb) 和 SetFlyBehaviour(FlyBehaviour fb);

具体代码如下,2个具体的鸭子类就可已说明问题了,偷懒起见GreenDuck就不测试了。

 1 using System;
 2 namespace StrategyPattern
 3 {
 4     public interface FlyBehaviour
 5     {
 6          void Fly();
 7     }
 8     public class FlyWithWings : FlyBehaviour
 9     {
10        public void Fly()
11         {
12             Console.WriteLine("我会飞");
13         }
14     }
15     public class FlyNoWay:FlyBehaviour
16     {
17         public void Fly()
18         {
19             Console.WriteLine("我不会飞");
20         }
21     }
22 }

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace StrategyPattern
 8 {
 9     public interface QuackBehaviour
10     {
11         void Quack();
12     }
13 
14     public class QuackLoudly:QuackBehaviour
15     {
16         public void Quack()
17         {
18             Console.WriteLine(("嘎嘎叫"));
19         }
20     }
21     public class QuackMute:QuackBehaviour
22     {
23         public void Quack()
24         {
25             Console.WriteLine("不会叫");
26         }
27            
28     }
29 }
 1 using System;
 2 
 3 namespace StrategyPattern
 4 {
 5     public  class Duck
 6     {
 7         public FlyBehaviour flyBehaviour;
 8         public QuackBehaviour quackBehaviour;
 9         protected string name = "duck";
10         public Duck()
11         {
12 
13         }
14         public Duck(string name)
15         {
16             this.name = name;
17         }
18         public void SetFlyBehaviuor(FlyBehaviour fb)
19         {
20             flyBehaviour = fb;
21         }
22         public void SetQuackBehaviour(QuackBehaviour qb)
23         {
24             quackBehaviour = qb;
25         }
26        
27         public void Swim()
28         {
29             Console.WriteLine(name + "鸭子在游泳");
30         }
31         public void PerformQuack()
32         {
33             Console.WriteLine(("I am" + name));
34             quackBehaviour.Quack();
35         }
36         public virtual void Display()
37         {
38             Console.WriteLine(name + "基类的display方法被调用");
39         }
40        public  void PerformFly()
41         {
42             Console.WriteLine(("I am" + name));
43             flyBehaviour.Fly();
44         }
45     }
46 }

测试类Client.

 1 using System;
 2 
 3 namespace StrategyPattern
 4 {
 5     class Client
 6     {
 7         static void Main(string[] args)
 8         {
 9             FlyBehaviour flyBehaviour = new FlyWithWings();         //定义一个会飞的行为
10             FlyBehaviour notFlyBehaviour = new FlyNoWay();          //定义一个不会飞的行为
11             QuackBehaviour quackBehaviour = new QuackLoudly();      //定义一个嘎嘎叫的行为
12             QuackBehaviour notQuackBehaviour = new QuackMute();     //定义以一个不会叫的行为
13 
14             Duck redDuck = new RedDuck("Mr.Red");
15             redDuck.SetFlyBehaviuor(flyBehaviour);                  //动态添加飞行行为
16             redDuck.PerformFly();
17             redDuck.SetQuackBehaviour(quackBehaviour);                  //动态添加嘎嘎叫行为
18             redDuck.PerformQuack();
19 
20            
21 
22             Duck rubberDuck = new RubberDuck("Mr.Rubber");
23             rubberDuck.SetFlyBehaviuor(notFlyBehaviour);
24             rubberDuck.PerformFly();
25             rubberDuck.SetQuackBehaviour(notQuackBehaviour);
26             rubberDuck.PerformQuack();
27 
28             Console.ReadKey();
29         }
30     }
31 }

技术分享图片

参考资料:《Head First 设计模式》

以上是关于Strategy 策略模式的主要内容,如果未能解决你的问题,请参考以下文章

22-策略(Strategy)模式Ruby实现

设计模式之- 策略模式(Strategy Pattern)

Java设计模式之策略模式(Strategy)

1.Strategy Pattern(策略模式)

设计模式:Strategy(策略)

23种设计模式之策略模式(Strategy)