设计模式---策略模式
今日在学习设计模式,深深地认识了自己的不足之处啊!!也认识到了一句话:“单纯为实现功能的代码不是好代码!”。我们必须要考虑到软件行业“多变”这个老魔头,时刻保持代码的可扩展性。为了丰富自己的羽翼,也为了能够和更多的人一起学习交流,写点东西吧!
策略模式
1、什么是策略模式?
策略模式定义了算法族,分别封装起来。让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
2、策略模式设计原则?
2.1 封装“变化”,使易于变化的部分独立于不变的部分,以便修改“变化”时,其他部分不受影响。
2.2针对“接口”编程而非针对实现编程。针对“接口”编程就是针对“超类型”编程,这个“超类型”可以是“接口《interface》“也可以是”抽象类《abstract class》”。
2.3多用组合,少用继承。可能随着你的编程技术的成熟,你会越来越发现,继承是有弊端的,如:代码在多个子类中重复,运行时的行为不容易改变,
改变会牵一发动全身等等。 解决这个弊端的好方法之一就是使用组合。
3、如何实现策略模式?
3.1封装“变化”,针对“接口”编程
实现策略模式很简单,按照策略模式设计原则,我们应该把基类中易于变化的“东西”拿出来,这一部分封装成“接口”或者“抽象类”。那么我们所谓的“方法族”就是实现这个接口(或抽象类)的具体的类。比如,基类是某游戏中的“鸭子”类,我们知道所有鸭子都可以游泳,但不是所有鸭子都能呱呱叫,比如橡皮鸭子,他只会吱吱叫;也不是所有鸭子都能飞翔,橡皮鸭子就不会飞。又如,在游戏中,我们通常要加入魔幻场景,比如让鸭子借助火箭力量飞起来等。显然要用继承实现不是最好的。我们应该抽象出“飞”的行为,FlyBehavior,这个接口提供一个fly()方法。让那些飞,不会飞,借助火箭飞等等这些方法作为具体类族来实现这个接口。同理,“叫”(QuackBehavior)也是如此。这里就会有人问了,类不是对现实世界的抽象吗?不是把某个“东西”抽象吗?怎么方法也抽象出类了?对了!你说的没错,只不过,在这的这个“东西”就是个行为。
3.2利用组合
我们把变化的部分从基类中拿出来了,怎么把它放回去呢?——组合!在鸭子类这个基类中,添加一个FlyBehavior的对象,同理还有QuackBehavior的对象。这样,每个鸭子类的子类就都具有了FlyBehavior和QuackBehavior的对象。我们再给基类鸭子类中添加flyBehavior和quackBehavior的setter方法,以便可以运行时动态设置flyBehavior和quackBehavior。
4、策略模式类图
每次在着手写代码前画好类图是一个非常好的编程习惯。
先来看一下通用的策略模式类图:
在这里,Strategy就是接口,它定义了一个方法AlgorithmInterface,ConcreteStrageA,ConcreteStrageB,ConcreteStrageC都是具体的策略,要实习这个AlgorithmInterface方法。Context就是我们的基类,他要维护一个Strategy的对象。将来在写客户调用代码时,就可以根据需要来初始化这个Strategy的对象了。
下面我们来看一下刚才跟鸭子有关系的小游戏的类图
5、实现代码:
1 //定义飞行方法族 2 3 public interface FlyBehavior 4 { 5 void fly(); 6 } 7 8 public class FlyWithWings:FlyBehavior 9 { 10 public void fly() 11 { 12 Console.WriteLine("我有翅膀,可以飞翔"); 13 } 14 } 15 class FlyWithRocketPower:FlyBehavior 16 { 17 public void fly() 18 { 19 Console.WriteLine("我可以借助火箭的力量飞翔"); 20 } 21 } 22 public class FlyNoWay:FlyBehavior 23 { 24 public void fly() 25 { 26 Console.WriteLine("我不会飞!"); 27 } 28 }
1 //定义“叫”方法族 2 public interface QuackBehavior 3 { 4 void quack(); 5 } 6 public class MuteQuack:QuackBehavior 7 { 8 public void quack() 9 { 10 Console.WriteLine("我不会叫!"); 11 } 12 } 13 public class Quack:QuackBehavior 14 { 15 public void quack() 16 { 17 Console.WriteLine("我会呱呱叫!"); 18 } 19 } 20 public class Quack:QuackBehavior 21 { 22 public void quack() 23 { 24 Console.WriteLine("我会呱呱叫!"); 25 } 26 }
//鸭子基类 public class Duck { public FlyBehavior flyBehavior; public QuackBehavior quackBehavior; public void swim() { Console.WriteLine("我会游泳"); } public virtual void display() { } public void performFly() { this.flyBehavior.fly(); } public void performQuack() { this.quackBehavior.quack(); } public void setFlybehavior(FlyBehavior fly) { this.flyBehavior = fly; } public void setQuackbehavior(QuackBehavior quack) { this.quackBehavior = quack; } } //诱饵鸭 public class DecoyDuck:Duck { public DecoyDuck() { this.flyBehavior = new FlyNoWay(); this.quackBehavior = new Quack(); } public override void display() { Console.WriteLine("我是诱饵鸭!"); } } //橡皮鸭 public class RubberDuck:Duck { public override void display() { Console.WriteLine("我是橡皮鸭"); } public RubberDuck() { this.flyBehavior = new FlyNoWay(); this.quackBehavior = new Squeak(); } } //红头鸭 public class RedheadDuck:Duck { public override void display() { Console.WriteLine("我是红头鸭!"); } public RedheadDuck() { this.flyBehavior = new FlyWithWings(); this.quackBehavior = new Quack(); } } //绿头鸭 public class MallardDuck:Duck { public override void display() { Console.WriteLine("我是绿头鸭!"); } public MallardDuck() { this.flyBehavior = new FlyWithWings(); this.quackBehavior = new Quack(); } }
//测试代码 class Program { static void Main(string[] args) { Duck redduck = new RedheadDuck(); redduck.performFly(); redduck.performQuack(); redduck.setFlybehavior(new FlyWithRocketPower()); redduck.performFly(); Console.ReadKey(); } }
关于策略模式一书《HEAD FIRST》中的动作冒险游戏代码可以给我发邮件(13623215228@163.com)