7. 策略者模式(Stragety Pattern)

 

策略者模式(Stragety Pattern

 
一、概念
 
                概念:将每个算法封装到不同的策略类中,使他们可以互换替换。
 
                举例:中国所得税,分为企业所得税、外商企业所得税、个人所得税,针对每一种税收都有不同的计算方式,所以不使用策略模式来实现这一需求的话,我们就得建一个计算税收的CalculateTax()方法,在该方法内对税收类型作出判断,通过if-else语句来针对不同的税收类型来计算所得税,这样的确可以解决问题,但是不利于扩展。如果系统后期再增加一种所得税,那我们不得不去修改CalculateTax()方法,添加一个判断语句,这样就违背了面向对象的“开放----封闭”原则(对扩展开放,对修改封闭)。此时,我们考虑使用“策略这模式”来解决这一问题。既然税收方法在这个场景中是一个变化的部分,那我们可以考虑将税收方法抽象出来。
 
               .NET中的应用:为集合类型ArrayList 和 List<T>提供的排序功能,其中实现就利用了策略者模式。定义了ICompare接口来对比较算法进行封装,实现ICompare接口的类可以使顺序,也可以是倒序比较俩个对象。其中List<T>就是承担着环境的角色,而 ICompare<T> 承担着抽象策略的角色,具体的策略角色就是实现ICompare接口的类。
 
二、结构图
 
该模式涉及到的角色:
  • 环境角色(Context):持有一个Strategy类的引用。起到配置维护调度的作用,由他来决定调用哪一个策略。
  • 抽象策略角色(Strategy): 这是一个抽象的角色,通常由一个接口或抽象类实现,此角色给出所有具体策略类所实现的接口。
  • 具体策略类角色(ConcreteStrategy): 包装了相关算法或行为。
                                   
 
三、使用场景
  • 一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口。
  • 如果一个对象有很多的行为,如果不使用合适的模式,这些行为就只好使用多重的if-else语句来实现,此时,可以使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象涉及的概念
四、优缺点比较
 
策略模式的主要优点有:
  • 策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换。
  • 易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。
  • 避免使用多重条件选择语句,充分体现面向对象设计思想。
策略模式的主要缺点有:
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式会造成很多的策略类。
  • Strategy和Context之间的通信开销 :无论各个 ConcreteStrategy实现的算法是简单还是复杂, 它们都共享Strategy定义的接口。因此很可能某些 ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的 ConcreteStrategy可能不使用其中的任何信息!这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样问题 , 那么将需要在Strategy和Context之间更进行紧密的耦合。
     
五、C#代码实现
 
抽象算法类
abstract class Strategy
{
    //算法
    public abstract voidAlgorithmInterface();

}
//具体算法A
class ConcreteStrategyA : Strateg
{
    //实现算法A
    public override void AlgorithmInterface()
    {
        Console.WriterLine("This is out by ConcreteStrategyA..")
    }
}

//具体算法B
class ConcreteStrategyB : Strateg
{
    //实现算法B
    public override void AlgorithmInterface()
    {
        Console.WriterLine("This is out by ConcreteStrategyB..")
    }
}
//上下文
class Context
{
    Strategy strategy;
    public Context(Strategy strategy)
    {
        //初始化时传入具体的策略对象
        this.strategy= strategy;
    }

    //上下文接口
    //具体算法调用其算法的方法
    public void ContextInterface()
    {
        strategy.AlgorithmInterface();
    }
}
//客户端
static void Main(string args[])
{

    Context context;

    context= new Context(newConcreteStrategyA());
    context.ContextInterface();

    context= new Context(newConcreteStrategyB());
    context.ContextInterface();

    Console.read();
}
 
六、与状态模式的区别
 
策略模式和状态模式最大的区别就是策略模式只是根据条件的选择只执行一次,而状态模式是随着实例参数(对象实例的状态)的改变不停地更改执行模式。
换句话说,策略模式只是在对象初始化的时候更改执行模式,而状态模式是根据对象实例的周期时间而动态地改变对象实例的执行模式。
 
 
七、总结
 
策略模式仅仅封装算法,提供新算法插入到已有系统中以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。
 
 
 
 
 
 
posted @ 2019-05-01 08:00  NCat  阅读(194)  评论(0)    收藏  举报