意图
将算法封装,使系统可以更换或扩展算法。策略模式的关键是所有子类的目标一致,但是实现的方法不同。
使用场合
算法有多种变体可以使用。
多个相似的类仅仅因为行为不同,这时可以将这些类合并并采用策略模式处理这些行为。
一个类的某些行为有过多分支,这时可以将这些行为封装为不同的算法。
希望隐藏算法中采用的数据。
下面是可以使用策略模式的一些具体算法:
采用不同的算法压缩数据。
采用不同的方式对同样的数据绘图,如直方图、折线图或饼分图。
以不同的格式保存数据,如将对象序列化为XML或者二进制格式并保存。
结构
Strategy:定义需要支持的算法的接口,由策略上下文接口调用。
ConcreteStrategy:包含算法的具体策略。
strateinterface:外界用户通过这个接口访问某一个特定的算法,这个接口引用策略对象,并定义一个接口是策略访问其数据。
Context:Strategy的客户。
效果
策略模式使得针对一个问题可以有多个解决方案。
计算库存下限
问题
假设我们在开发一个库存管理软件,目标是通过统计库存变化得出最小的保存库存。
以满足生产前提条件下尽可能地降低库存,达到降低资金占有,降低成本的目的。
但是具体的算法有很多种,不同企业可能会使用不同的算法。
这里我们将采用策略模式来实现程序对多种算法的支持。
结构
采用策略模式计算最小库存的结构如下图
采用车略模式实现最小库存的算法互换和扩展,这里列出3种计算方法,即按照最小输出计算(CompMinStoreByMinOutput),按照最大日输出计算(CompMinStoreByMaxOutputPerDay)和按照平均日输出计算(CompMinStoreByAvgOutput)。
实现
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex324
{
public abstract class CompMinStore
{
public abstract long Comp(StoreContext sc);
}
}
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex324
{
public class StoreContext
{
private long _minOutputPerDay;
private long _maxOutputPerDay;
private CompMinStore _cs;
public long MinOutputPerDat
{
get { return _minOutputPerDay; }
set { _minOutputPerDay = value; }
}
public long MaxOutputPerDay
{
get { return _maxOutputPerDay; }
set { _maxOutputPerDay = value; }
}
public CompMinStore CompStrategy
{
get { return _cs; }
set { _cs = value; }
}
public long Comp()
{
return _cs.Comp(this);
}
}
}
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex324
{
class CompMinStoreByMaxOutputPerDay : CompMinStore
{
public override long Comp(StoreContext sc)
{
return (sc.MinOutputPerDat + sc.MinOutputPerDat) / 2 * 10;
}
}
}
......
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex324
{
public class CompMinStoreByMinOutputPerDay:CompMinStore
{
public override long Comp(StoreContext sc)
{
return sc.MaxOutputPerDay * 10;
}
}
}
{
StoreContext sc = new StoreContext();
sc.MinOutputPerDat = 20;
sc.MaxOutputPerDay = 50;
CompMinStore s;
s = new CompMinStoreByMaxOutputPerDay();
sc.CompStrategy = s;
Console.WriteLine(sc.CompStrategy.GetType().ToString() + ":" + sc.Comp());
s = new CompMinStoreByMinOutputPerDay();
sc.CompStrategy = s;
Console.WriteLine(sc.CompStrategy.GetType().ToString() + ":" + sc.Comp());
......
}
采用委托技术的策略模式
在.NET平台下,策略模式的一种替代方式或者说变体是采用委托技术。采用委托技术解除了Context与策略类之间的耦合,甚至实现策略的具体类都可以不是相同的父类,只要与策略相关的方法接口相同即可。
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex325
{
public delegate void strategy();
public class ContextUsingDelegate
{
public strategy myStrategy;
public void ContextInterface()
{
myStrategy();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace StrategyPattern.ex325
{
public class StrategyClass
{
public void ConcreteStrategy()
{ }
}
}
{
StrategyClass sc = new StrategyClass();
ContextUsingDelegate cud = new ContextUsingDelegate();
cud.myStrategy = new strategy(sc.ConcreteStrategy);
cud.ContextInterface();
}
采用这种方式可以实现策略模式的意图,并且更加灵活,可以减少接口,更有效的复用现有的类。
相关模式
享元模式:可以将策略作为享元,因为策略通常是轻量级对象。
装饰模式:通过为对象增加包装扩展对象的功能,而策略通过修改内部算法改变对象的功能。