策略模式(Strategy)
先来看一副 Class Diagram
上面这副类图呢,表明,如果您要上学的话,你有四种策略,
您可以走路去,可以坐公交车,可以骑自行车,可以开私家车,
上面的即是一个最简单的策略模式结构图了
先来明白一下聚合关系是什么?
比如 A 对象可以包含 B 对象,但 B 对象不是 A 对象的一部分,则 A 和 B 之间就是一种聚合关系。
比如一个人是属于一个家庭的,而一个家庭可以有多个人,
同时,一个人可以属于多个家庭(自己的家庭,和父母的家庭),
所以人和家庭是聚会关系。
从上面可以很明显的看出,策略和上学是一种聚合关系,
您上学必须要有一个策略(一种上学的方法)才行,而策略(上学的方法)却是独立的,
我走路归走路,和上学没有联系的,是独立的,而上学的话,您必须选一种方式(策略)才能实现。
再来给出策略模式的定义
策略模式定义了算法族,也就是定义了一系列的算法,并分别对这些算法进行了封装,
让这些算法之间可以互换,
这个模式的优点在于,当面对算法经常需要改变时,
这个模式可以让算法的变化独立于使用算法的客户,
也就是说,这个模式可以让算法的变化不会影响到使用算法的客户。
同时由于各个算法类是独立的,从而减少了各种算法类与使用算法类(客户)之间的耦合度。
拿上面的“上学”这个例子来看的话,
我定义了一个策略的基类(一般应定义为抽象类或者是接口),
然后在这个基类下又定义了四个独立的子类,其实,这四个子类就是算法了,
由于四种算法都被封装在了单独的类中,并且都继承自”策略“这个基类,
所以可以让这些算法之间进行互换,由于在客户(也就是“上学”)和算法(策略)之间是聚合关系,
所以这些算法的变化独立于使用算法的客户(上学)。
上面的这幅图就是策略模式的结构图了
下面就完成一个 Demo ,即使用策略模式来完成最开始的“上学”问题:
上面的截图就是关于“上学”问题的具体结构图了,
其中,定义了四个算法,分别计算出上学所要花费的时间,
而在 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();
}
}
}
下面就可以给出效果的截图了
从上面的策略模式 Demo 可以看出,我可以在客户端 Main 函数中更改算法,
而客户 GoToSchool 类却并不会受到影响,
甚至它都并不知道,客户端中的算法已经改变了,
同时,也可以看出算法是可以互相替换的,这主要是因为各个算法被封装在了独立的类中,
而这些正是策略模式的优点所在~~~