策略模式(Strategy Pattern)
策略模式定义了一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。别名:Policy(方针)
结构:
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy
{
abstract class Strategy
{
public abstract void AlgorithmInterface();
}
class ConcreteStrategyA : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("Algorithm A implementation");
}
}
class ConcreteStrategyB : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("Algorithm B implementation");
}
}
class ConcreteStrategyC : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("Algorithm C implementation");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy
{
class Context
{
private Strategy strategy;
public Context(Strategy strategy)
{
this.strategy = strategy;
}
public void ContextInterface()
{
strategy.AlgorithmInterface();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy
{
class Program
{
static void Main(string[] args)
{
Context context;
context = new Context(new ConcreteStrategyA());
context.ContextInterface();
context = new Context(new ConcreteStrategyB());
context.ContextInterface();
context = new Context(new ConcreteStrategyC());
context.ContextInterface();
Console.ReadKey();
}
}
}
参与者:Strategy( 策略 )
— 定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
• ConcreteStrategy(具体策略)
— 以Strategy接口实现某具体算法。
• Context(上下文)
— 用一个ConcreteStrategy对象来配置。
— 维护一个对Strategy对象的引用。
— 可定义一个接口来让Strategy访问它的数据。
效果:
1)相关算法系列Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
2) 一个替代继承的方法。继承提供了另一种支持多种算法或行为的方法。你可以直接生成一个Context类的子类,从而给它以不同的行为。但这会将行为硬行编制到 Context中,而将算法的实现与Context的实现混合起来 , 从而使Context难以理解、难以维护和难以扩展,而且还不能动态地改变算法。最后你得到一堆相关的类 , 它们之间的唯一差别是它们所使用的算法或行为。将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、易于理解、易于扩展。
3) 消除了一些条件语句。Strategy模式提供了用条件语句选择所需的行为以外的另一种选择。当不同的行为堆砌在一个类中时 , 很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的Strategy类中消除了这些条件语句。
实现:
1)定义Strategy和Context接口
一种办法是让Context将数据放在参数中传递给Strategy操作——也就是说, 将数据发送给Strategy。这使得Strategy和Context解耦。另一种办法是让Context将自身作为一个参数传递给Strategy, 该Strategy再显式地向该Context请求数据。或者,Strategy可以存储对它的Context的一个引用, 这样根本不再需要传递任何东西。
2)将Strategy作为模板参数
template <class AStrategy>
class Context
{
public
void Operation()
{
theStrategy.DoAlgorithm();
}
private:
AStrategy theStrategy;
}
class MyStrategy
{
public:
void DoAlgorithm();
}
Context<MyStrategy> myContext;
可以在编译时选择Strategy,不需要在运行时改变,提高效率。
3)使Strategy对象称为可选
实际应用代码:
商场购物结账,根据不同的付账方式,选择不同的计算策略。CashContext用到了简单工厂,下面代码中策略模式与简单工厂相结合,降低了代码的耦合性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy1
{
abstract class CashSuper
{
public abstract double acceptCash(double money);
}
class CashNormal : CashSuper
{
public override double acceptCash(double money)
{
return money;
}
}
class CashRebate : CashSuper
{
private double moneyRebate = 1d;
public CashRebate(string moneyRebate)
{
this.moneyRebate = double.Parse(moneyRebate);
}
public override double acceptCash(double money)
{
return money * moneyRebate;
}
}
class CashReturn : CashSuper
{
private double moneyCondition = 0.0d;
private double moneyReturn = 0.0d;
public CashReturn(string moneyCondition, string moneyReturn)
{
this.moneyCondition = double.Parse(moneyCondition);
this.moneyReturn = double.Parse(moneyReturn);
}
public override double acceptCash(double money)
{
double result = money;
if (money >= moneyCondition)
{
result = money - Math.Floor(money / moneyCondition) * moneyReturn;
}
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy1
{
class CashContext
{
CashSuper cs = null;
public CashContext(string type)
{
switch (type)
{
case "正常收费":
CashNormal cs0 = new CashNormal();
cs = cs0;
break;
case "满300返100":
CashReturn cr1 = new CashReturn("300", "100");
cs = cr1;
break;
case "打8折":
CashRebate cr2 = new CashRebate("0.8");
cs = cr2;
break;
}
}
public double GetResult(double money)
{
return cs.acceptCash(money);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyStrategy1
{
class Program
{
static void Main(string[] args)
{
double totalPrices = 100d;
string cashType = "打8折";
CashContext csuper = new CashContext(cashType);
totalPrices = csuper.GetResult(totalPrices);
Console.ReadKey();
}
}
}
参考《设计模式》、《大话设计模式》,进行整理。