述:

      策略模式属于对象的行为模式(has-a, not is-a)。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

意图:

  • 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。
  • 策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
  • 运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

 

参与者:

  • 环境(Context)角色:需要使用ConcreteStrategy提供的算法;内部维护一个Strategy的实例;负责动态设置运行时Strategy具体的实现算法;负责跟Strategy之间的交互和数据传递。
  • 抽象策略(Strategy)角色:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  • 具体策略(ConcreteStrategy)角色:实现了Strategy定义的接口,提供具体的算法实现。

UML图:

实质:

  策略模式中的Context类的功能基本上就是对工厂类的强化版本,它也负责根据输入参数来生成不同的类,只是它并不返回生成类,而是将生成类所实现的功能接口包装一次,提供给客户。这样对客户来说,他们只需要知道这一个Context类就可以完成他们想要的功能,而不必再知道其他的信息。

 

    public interface IStrategyA
    {
        //该方法对于Context来说,该行为不稳定,是动态的,如果在运行时才确定具体行为,所以用has-a 的关系会比is-a的关系好
        void AlgorithmA();
    }

    public interface IStrategyB
    {
        //该方法对于Context来说,该行为不稳定,是动态的,如果在运行时才确定具体行为,所以用has-a 的关系会比is-a的关系好
        void AlgorithmB();
    }

    public class StrategyA:IStrategyA{

        public void AlgorithmA()
        {
            //具体实现策略A
        }
    }

    public class StrategyAA : IStrategyA
    {
        public void AlgorithmA()
        {
            //具体实现策略AA
        }
    }

    public class StrategyB : IStrategyB
    {
        public void AlgorithmA()
        {
            //具体实现策略B
        }
    }

    public class StrategyBB : IStrategyB
    {
        public void AlgorithmB()
        {
            //具体实现策略BB
        }
    }

 

    public interface IAction
    {
        //该方法对于Context来说很稳定,该行为确定了,客户端不需要动态改变其行为,所以用is-a的关系会比has-a的关系好
        void Action();
    }

 

//AContext具备IAction、IStrategyA、IStrategyB接口行为
    public abstract class AContext:IAction
    {
        //如果IStrategy行为是不固定的。继承IStrategyA、IStrategyB方式也可以实现该功能,但是需要为每一个特殊的子类提供具体行为的实现。
        IStrategyA strategyA;
        //而且如果象这种IStrategy有多种的话,继承代码重用功力很差了
        IStrategyB strategyB;
        public AContext(IStrategyA strategyA,IStrategyB strategyB)
        {
            this.strategyA = strategyA;
            this.strategyB = strategyB;
        }

        public void ContextInterfaceA()
        {
            strategyA.AlgorithmA();
        }

        public void ContextInterfaceB()
        {
            strategyB.AlgorithmB();
        }

        public void Action()
        {
           //具体Action行为
        }
    }

优点:

  •  提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。

         我的理解:结合上序代码,如果多项行为在子类里持续不断地改变在运行时才确定,所以让所有的子类都拥有基类的行为是不适当的,而使用实现接口的方式,又破坏了代码重用。找到系统中变化的部分,将变化的部分同其它稳定的部分隔开。变化的部分就是子类里的行为,所以我们要把这部分行为封装起来,去动态地改变一个子类的行为,运行时确定具体子类实例的行为。通过继承的话我们则需要为每一个特殊的子类提供具体行为的实现。

  • 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
  • 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
  • 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

 

缺点:

  • 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
  • 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

使用场景:

  • 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
  • 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。(具体实现可任意变化或扩充)
  • 对客户(Duck)隐藏具体策略(算法)的实现细节,彼此完全独立。

简单工厂改进策略模式(也可以通过反射改进,这里不再介绍)

View Code
 //简单工厂改进策略模式(也可以通过反射改进,这里不再介绍)
    public abstract class AContextFactory : IAction
    {
        IStrategyA strategyA;
        IStrategyB strategyB;
        public AContextFactory(string typeA, string typeB)
        {
            switch (typeA)
            {
                case "StrategyA":
                    this.strategyA = new StrategyA();
                    break;
                case "StrategyAA":
                    this.strategyA = new StrategyAA();
                    break;
            }
            switch (typeB)
            {
                case "StrategyB":
                    this.strategyB = new StrategyB();
                    break;
                case "StrategyBB":
                    this.strategyB = new StrategyBB();
                    break;
            }
        }

        public void ContextInterfaceA()
        {
            strategyA.AlgorithmA();
        }

        public void ContextInterfaceB()
        {
            strategyB.AlgorithmB();
        }

        public void Action()
        {
            //具体Action行为
        }
    }

 

总结:以上纯属个人的理解,对于有些地方觉得还是理解不是很深,有不足之处和错误的地方希望大家帮我指出。谢谢

 

posted on 2012-12-17 18:38  雇佣兵333  阅读(1112)  评论(1编辑  收藏  举报