一、概述
策略模式:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法变化独立于使用算法客户。
--摘自《Head First设计模式》
二、策略模式:
我们用《Head First设计模式》一书中的例子分析一下为什么我们采用策略模式解决问题。
现在我们要开发一个鸭子的游戏,开始鸭子有游泳,叫,玩等行为。
我们用继承和多态来实现不同的鸭子执行不同的行为,在我们遇到一个问题,每增加一个类型的鸭子我们都需要重写类型内部发方法,最后发现很多重复代码。
这时,你的老板不高兴了,需要你做优化处理,首先我们考虑到接口:
但是接口实现过程中同样有过多的重复代码出现,没有从根本上解决代码堆积的问题。
这时策略模式就派上用场了,看一下类图:
显而易见,我们把可变的行为以接口继承的方式实现,行为接口与Duck类以组合形式存在。
三. 源码实现:
1. 飞行行为:
public interface FlyBehavior { string Fly(); } public class FlyWithWing:FlyBehavior { public string Fly() { return string.Format("I am flying!"); } } public class FlyNoWay:FlyBehavior { public string Fly() { return string.Format("I Can't fly!"); } } public class FlyRocketPowered:FlyBehavior { public string Fly() { return string.Format("I'm flying with a rocket!"); } }
2. 鸭叫行为:
public interface QuackBehavior { string quack(); } public class Quack:QuackBehavior { public string quack() { return string.Format("Quack!"); } } public class SQuack:QuackBehavior { public string quack() { return string.Format("SQuack!"); } } public class MuteQuack:QuackBehavior { public string quack() { return string.Format("MuteQuack!"); } }
3. 鸭子基类:
public abstract class Duck { protected FlyBehavior flyBehavior; protected QuackBehavior quackBehavior; public abstract string Display(); public string PerformFly() { return flyBehavior.Fly(); } public string PerformQuack() { return quackBehavior.quack(); } public void SetFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void SetQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public string Swim() { return string.Format("I'm Swimming!"); } }
4.鸭子子类:
public class MallardDuck:Duck { public MallardDuck() { flyBehavior = new FlyWithWing(); quackBehavior = new Quack(); } public override string Display() { return string.Format("I'm a real duck!"); } } public class ModelDuck:Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new MuteQuack(); } public override string Display() { return string.Format("I'm a model duck!"); } }
5.测试实现:
[TestClass] public class MallardDuckTest { [TestMethod] public void MallardDuckBehavior() { string expected = "Quack!"; Duck mallardDuck = new MallardDuck(); string actual= mallardDuck.PerformQuack(); Assert.AreEqual(expected,actual); expected = "I am flying!"; actual = mallardDuck.PerformFly(); Assert.AreEqual(expected, actual); expected = "I'm flying with a rocket!"; mallardDuck.SetFlyBehavior(new FlyRocketPowered()); actual = mallardDuck.PerformFly(); Assert.AreEqual(expected, actual); } }
四. 总结
我们用策略模式解决了那些问题:
1.代码在子类中的重复问题。
2.运行时行为不容易改变。
3.很难知道所有鸭子的行为。
4. 改变会牵一发而东全身,造成其他鸭子不想要的改变问题。
我们回顾一下OO的重要原则:
1. 封装变化。
2. 多用组合,少用继承。
3. 针对接口编程,不针对实现编程。