行者无疆
When I was young , I used to think that money was the most important thing in life , now I am old , I know it is.
Strategy Pattern(策略模式):
设想我们要开发一个鸭子游戏,我们设计了各种鸭子,鸭子会游泳,会叫,还有各种自己的外观。按照面对对象的设计,我们很

容易实现这个游戏,首先我们声明一个鸭子的基类 Duck,这个鸭子类如下:
  public class Duck
    {
        public void Swim()
        { }

        public void Quack()
        { }

        public virtual void Display()
        { }
    }
然后我们可以声明各种鸭子继承这个类,比如绿头鸭,红头鸭之类的。 它们都会叫,会游泳,但是有不同的外观,所以我们什么

Display为virtual,每个子类将自己实现它。
看上去很完美,我们遵循了面对对象的原则。但是有一天,市场人员告诉我们,鸭子要有更多的特性,有的鸭子要会飞,有点鸭

子则不能。第一感觉,很简单,在基类Duck中加上一个virtual方法Fly(),如果不需要鸭子会飞,那么我们在子类重载,把Fly设定

为不会飞。功能是实现了,但是我们会感到不爽,也许我们有30种鸭子不会飞,那么我们要在30个子类中做这件事,于是出现了

重复代码。于是第二选择,我们声明一个接口IFlyable,只有需要飞的鸭子,才需要实现这个接口。接口 仍然没有解决代码重用的

问题,我们需要给每个会飞的鸭子重写Fly方法。问题似乎麻烦了,而且很有可能有一天,市场人员会告诉我们鸭子飞行的姿势会

不一样,绿头鸭朝南飞,黑头鸭红头鸭朝北飞,我们需要提前考虑市场人员的需求,怎么办?软件开发中,亘古不变的永远是变

化,还记得我们的软件设计原则不? 封装变化,把需求中需要变化的提取出来,不要和不变的部分混合在一起。这样我们改变变

化的部分的时候,不会影响到不变的部分。提取变化并封装变化,参照软件设计原则,针对接口编程,而不是针对实现编程,所

以我们重新实现Duck,并声明接口IFlyable,实现接口,代码如下:
1. 声明接口:
public interface IFlyable
    {
        void Fly();
    }

2. 声明基类
 public abstract class Duck
    {
        public IFlyable FlyBehavior { set; get; }

        public void Swim()
        { }

        public void Quack()
        { }

        public virtual void Display()
        { }

        public void Fly()
        {
            FlyBehavior.Fly();
        }
    }

我们可以看到,在基类成了一个抽象类,多了一个接口对象 FlyBehavior ,在Fly方法中,我们调用了FlyBehavior的Fly方法。到此

为止,我们把Fly的方法彻底下放给接口的实现了。同时我们是不是也遵循了另外一个设计原则:尽量用have-a而不是is-a(多用组

合,少用继承).
3. 接口的实现
 public class FlyTowardSouth : IFlyable
    {

        public void Fly()
        {
            Console.WriteLine("Fly toward south");
        }
    }

    public class FlyTowardNorth : IFlyable
    {
        public void Fly()
        {
            Console.WriteLine("Fly toward North");
        }
    }

    public class FlyNoWay : IFlyable
    {
        public void Fly()
        {
            Console.WriteLine("Fly No way");
        }
    }
我们实现了向南飞,向北飞,不会飞,这样具体什么鸭子往哪边飞,我们只要不同的接口实现对象即可。
4. 真实的鸭子
 public class MallardDuck : Duck
    {
        public MallardDuck()
        {
            this.FlyBehavior = new FlyTowardNorth();
        }        
    }
看到没有,这只鸭子会向北飞,如果我们要它向南飞,只需要  this.FlyBehavior = new FlyTowardSouth();即可。
如果有一天,市场人员要我们开发向西飞的鸭子,我们只要实例化一个实现了向西飞的接口即可。

这就是策略模式,使用策略模式,我们是不是实现了代码的重用,提高了软件的灵活性?

 

最后是策略模式的定义:策略模式抽取算法,并分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

posted on 2009-03-30 15:49  衣不如新  阅读(932)  评论(0编辑  收藏  举报