3-7设计模式之策略模式(Strategy)

3.7.1 模式意图:

如果在系统中需要为某一行为提供多种方案,例如不同的折扣方式;货币不同的汇率;到达某地不同的路线等情况,就可以使用策略模式。

3.7.2 模式概念:

它属于行为型模式,指对象有某个行为,但是在不同的环境中,可以在运行时为行为更改不同的算法。

3.7.3 模式元素:

  • 策略抽象(BaseStrategy)
  • 策略细节(StrategyWalk、StrategyShip等)
  • 使用环境(Context)

3.7.4 代码示例:

public abstract class BaseStrategy
{
   public abstract string GetRoute(string from, string to);
}

public class StrategyWalk : BaseStrategy
{
    public override string GetRoute(string from, string to)
    {
        return "步行到达";
    }
}

public class StrategyShip : BaseStrategy
{
    public override string GetRoute(string from, string to)
    {
        return "轮船到达";
    }
}

public class StrategyTrain : BaseStrategy
{
    public override string GetRoute(string from, string to)
    {
        return "火车到达";
    }
}

public class StrategyAirplane : BaseStrategy
{
    public override string GetRoute(string from, string to)
    {
        return "飞机到达";
    }
}
public class Context 
{
    private BaseStrategy baseStrategy;

    public Context(BaseStrategy baseStrategy)
    {
        this.baseStrategy = baseStrategy;
    }
    public string GetResult(string side1,string side2)
    {
        return baseStrategy.GetRoute(side1, side2);
    }
}

调用示例代码

    void Start()
    {
        BaseStrategy strategy = new StrategyWalk();
        Context context = new Context(strategy);
        string route = context.GetResult("地点一", "地点二");
        Debug.Log(route);
    }

但是根据迪米特法则我们知道,对应类与类之间的关系,越少越好,如果我们的策略越多,那么上层业务逻辑需要知道的策略类也会随之增加,所以我们需要再次封装转移。

public class Context 
{
    private BaseStrategy baseStrategy;

    public Context(string strategy)
    {

        switch (strategy)
        {
            case "步行":
                this.baseStrategy = new StrategyWalk();
                break;
            case "轮船":
                this.baseStrategy = new StrategyShip();
                break;
            case "火车":
                this.baseStrategy = new StrategyTrain();
                break;
            case "飞机":
                this.baseStrategy = new StrategyAirplane();
                break;
            default:
                break;

        }
    }
    public string GetResult(string side1,string side2)
    {
        return baseStrategy.GetRoute(side1, side2);
    }
}

执行

    void Start()
    {
        Context context = new Context("飞机");
        string route = context.GetResult("地点一", "地点二");
        Debug.Log(route);
    }

这样上层只需要知道Context一个类就可以了,其他的都转移到下层执行。

3.7.5 写法对比:

3.7.6 模式分析:

根据定义的算法族可以使算法自由切换,扩展方便,但随着算法类的增多,contenxt中的算法也会逐渐增加,提高了出错的机率,届时需要对算法族再次封装(例:按类别),减少相互的干扰。

3.7.7 应用场景:

需要为一种行为提供不同的策略来达到获取不同结果的目的。

3.7.8 小结:

对于策略的选择是放到Context里面还是放到上层业务逻辑中需要根据实际情况自行权衡,但目的是一致的,就是减少类与类之间的依赖关系,降低其耦合度。而且在开发中可以将不同的算法以序列化的形式保存,例如ScriptableObjects,这样算法无需关心外部的环境而独立的保存。


12:13

更多设计模式详见:设计模式全家桶

发表评论