您的位置:首页 > 其它

设计模式——策略模式

2014-06-23 11:30 113 查看
定义:

定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

包含元素:

—抽象策略角色(Strategy): 策略类,通常由一个接口或者抽象类实现。

—具体策略角色(ConcreteStrategy):包装了相关的算法和行为。

—环境角色(context):持有一个策略类的引用,最终给客户端调用。

UML图如下:



就以商场打折促销为例:

针对不同的物品实行不同的收费制度(包括折扣、返利等)



代码部分:

//Strategy(策略类)和ConcreteStrategy(具体策略类)
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;
    }
}
//Context(环境角色,给客户端调用)
class CashContext
        {
            CashSuper cs = null;   //声明一个CashSuper对象
            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);
            }
        }
//客户端代码
double total = 0.0d;
private void btnOk_Click(object sender, EventArgs e)
{
    CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
    double totalPrices = 0d;
    totalPrices = csuper.GetResult (Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
    total = total + totalPrices;
    lbxList .Items .Add ("单价: "+txtPrice .Text +" 数量:"+txtNum .Text +" "+cbxType .SelectedItem +" 合计: "+totalPrices .ToString ());
    lblResult .Text =total.ToString ();
    txtPrice.Clear ();
    txtNum.Clear();
    txtPrice.Focus();
}


优缺点:

优点

1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。

2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。

3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

缺点

1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

使用场景:

1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2. 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。

3. 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。

4. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。

小结:

策略模式用来封装一系列算法,然后根据你给出对应的对象来执行对应的算法(方法)。如果说工厂模式关注对象的创建,策略模式则关注行为的选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: