策略模式(Strategy)

先来看一副 Class Diagram

image

上面这副类图呢,表明,如果您要上学的话,你有四种策略,

您可以走路去,可以坐公交车,可以骑自行车,可以开私家车,

上面的即是一个最简单的策略模式结构图了

先来明白一下聚合关系是什么?

比如 A 对象可以包含 B 对象,但 B 对象不是 A 对象的一部分,则 A 和 B 之间就是一种聚合关系。

比如一个人是属于一个家庭的,而一个家庭可以有多个人,

同时,一个人可以属于多个家庭(自己的家庭,和父母的家庭),

所以人和家庭是聚会关系。

从上面可以很明显的看出,策略和上学是一种聚合关系,

您上学必须要有一个策略(一种上学的方法)才行,而策略(上学的方法)却是独立的,

我走路归走路,和上学没有联系的,是独立的,而上学的话,您必须选一种方式(策略)才能实现。

再来给出策略模式的定义

策略模式定义了算法族,也就是定义了一系列的算法,并分别对这些算法进行了封装,

让这些算法之间可以互换,

这个模式的优点在于,当面对算法经常需要改变时,

这个模式可以让算法的变化独立于使用算法的客户,

也就是说,这个模式可以让算法的变化不会影响到使用算法的客户。

同时由于各个算法类是独立的,从而减少了各种算法类与使用算法类(客户)之间的耦合度。

拿上面的“上学”这个例子来看的话,

我定义了一个策略的基类(一般应定义为抽象类或者是接口),

然后在这个基类下又定义了四个独立的子类,其实,这四个子类就是算法了,

由于四种算法都被封装在了单独的类中,并且都继承自”策略“这个基类,

所以可以让这些算法之间进行互换,由于在客户(也就是“上学”)和算法(策略)之间是聚合关系,

所以这些算法的变化独立于使用算法的客户(上学)。

image

上面的这幅图就是策略模式的结构图了

下面就完成一个 Demo ,即使用策略模式来完成最开始的“上学”问题:

image

上面的截图就是关于“上学”问题的具体结构图了,

其中,定义了四个算法,分别计算出上学所要花费的时间,

而在 GoToSchool 中则通过维护一个 StudentStrategy 的实例来获取所需要花费的时间。

先来看策略抽象类 Strategy

namespace Strategy
{
    /// <summary>
    /// 定义抽象算法类(策略抽象类)
    /// </summary>

    abstract public class Strategy
    {
        /// <summary>
        /// 定义一个抽象算法
        /// 其所有的子类必须以自己的方式实现这个方法
        /// </summary>
        /// <returns></returns>

        abstract public double TotalTime();
    }
}

再来看具体策略类 Walk

namespace Strategy
{
    public class Walk:Strategy
    {
        public override double TotalTime()
        {
            return 56.5;
        }
    }
}

具体策略类 Bike

namespace Strategy
{
    public class Bike:Strategy
    {
        public override double TotalTime()
        {
            return 35;
        }
    }
}

具体策略类 Bus

namespace Strategy
{
    public class Bus:Strategy
    {
        public override double TotalTime()
        {
            return 22.5;
        }
    }
}

具体策略类 Sedan

namespace Strategy
{
    public class Sedan:Strategy
    {
        public override double TotalTime()
        {
            return 10;
        }
    }

}

客户类 GoToSchool

namespace Strategy
{
    public class GoToSchool
    {
        //在这个客户类中必须维护一个算法策略对象
        private Strategy strategy;

        public GoToSchool(Strategy strategy)
        {
            this.strategy = strategy;
        }

        public double GetTotalTime()
        {
            //利用多态
            return this.strategy.TotalTime();
        }
    }
}

最后就是客户端的 Main 函数咯

using System;
using Strategy;

namespace StrategyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Strategy.GoToSchool goToSchool =
new GoToSchool(new Walk());
            Console.WriteLine("走路所花的时间:{0}", goToSchool.GetTotalTime());

            goToSchool = new GoToSchool(new Bike());
            Console.WriteLine("自行车花的时间:{0}", goToSchool.GetTotalTime());

            goToSchool = new GoToSchool(new Bus());
            Console.WriteLine("公交车花的时间:{0}", goToSchool.GetTotalTime());

            goToSchool = new GoToSchool(new Sedan());
            Console.WriteLine("小轿车花的时间:{0}", goToSchool.GetTotalTime());
            Console.ReadKey();
        }
    }
}

下面就可以给出效果的截图了

image

从上面的策略模式 Demo 可以看出,我可以在客户端 Main 函数中更改算法,

而客户 GoToSchool 类却并不会受到影响,

甚至它都并不知道,客户端中的算法已经改变了,

同时,也可以看出算法是可以互相替换的,这主要是因为各个算法被封装在了独立的类中,

而这些正是策略模式的优点所在~~~

 

posted @ 2010-05-02 14:36  小宝马的爸爸  阅读(1483)  评论(0编辑  收藏  举报