• 策略模式


    策略模式的定义:

      策略模式(Strategy Pattern)也叫做政策模式(Policy Pattern)其定义:定义一组算法,将他们封装起来,使它们可以相互替换。

     

    策略模式的优点:

      1. 算法直接可以相互替换。这是因为策略都实现策略接口。

      2. 可以避免多重条件的情况出现。假设一个策略家族有N个成员,当一会需要策略A,另一会需要策略B,不使用策略模式的话,只能使用ifelse或switch语句实现,但是这样的程序不容易维护,可读性也比较差。使用策略模式后可以由其他模块确定策略。

      3. 有良好的扩展性。增加一个策略,只需要实现策略接口,就这么简单。

     

    策略模式的缺点:

      1. 子类膨胀,一个策略一个类,策略类的数量比较惊人。

      2. 调用者必须知道所有具体策略的存在(调用一个策略还需要自己new出来)。 

     

    策略模式的应用场景:

      1. 多个类只在算法或行为稍有不同(在抽象概念上是相同的行为)。

      2. 算法需要自由切换。 

     

    策略模式的通用类图:

     

    Strategy(抽象策略角色):定义了每个算法必须有的算法和属性。

    StrategyA(具体策略角色):实现了抽象策略定义的接口。

    Context(封装角色):将策略封装起来,屏蔽了调用者直接访问具体策略。

     

    策略模式的通用代码:

    抽象策略角色: 

    public interface Strategy
    {
    public void operation();
    }

    具体策略角色:

    复制代码
    public class StrategyA implements Strategy
    {
    @Override
    public void operation()
    {
    System.out.println("strategyA");
    }
    }
    复制代码

    封装角色:

    复制代码
    public class Context
    {
    private Strategy strategy = null;

    public Context(Strategy strategy)
    {
    this.strategy = strategy;
    }

    /*实现策略可以相互替换*/
    public void replaceStrategy(Strategy strategy)
    {
    this.strategy = strategy;
    }

    /*封装角色提供接口,让调用使用策略,屏蔽高层模块直接使用策略*/
    public void execute()
    {
    this.strategy.operation();
    }
    }
    复制代码

    场景类:

    复制代码
    public class Client
    {
    public static void main(String[] args)
    {
    /*这里可以看出策略模式的缺点,调用者必须要知道调用的策略(自己new出来StrategyA的对象)*/
    Context context = new Context(new StrategyA());
    context.execute();

    /*可以实现自由切换策略*/
    context.replaceStrategy(new StrategyB());
    context.execute();
    }
    }
    复制代码

     


    举个比较简单的例子理解策略模式 

    例子:"实现一个可以计算两个整数加减乘除计算的功能"。

    实现一:不使用策略模式

    复制代码
    class Calculator
    {
    /*代表加减乘除的字符串,用于判断使用什么计算策略*/
    private final static String ADD_SYMBOL = "+";
    private final static String SUB_SYMBOL = "-";
    private final static String MUL_SYMBOL = "*";
    private final static String DIV_SYMBOL = "/";

    /*策略选择函数,operator字符串参数用于判断,a、b两个参数使用的计算策略*/
    public int execute(int a,int b,String operator)
    {
    int result = 0;
    if(ADD_SYMBOL.equals(operator))
    {
    result = this.add(a, b);
    }
    else if(SUB_SYMBOL.equals(operator))
    {
    result = this.sub(a, b);
    }
    else if(MUL_SYMBOL.equals(operator))
    {
    result = this.multi(a, b);
    }
    else if(DIV_SYMBOL.equals(operator))
    {
    result = this.div(a, b);
    }

    return result;
    }

    /*加法功能实现*/
    private int add(int a,int b)
    {
    return a+b;
    }

    /*减法功能实现*/
    private int sub(int a,int b)
    {
    return a-b;
    }

    /*乘法功能实现*/
    private int multi(int a,int b)
    {
    return a*b;
    }

    /*除法功能实现*/
    private int div(int a,int b)
    {
    //只是为了说明问题,除数为0就不考虑了
    return a/b;
    }
    }
    复制代码

      这个实现比较容易想到,通过"operator"这个参数决定使用什么计算策略。这样的实现看上去完美的处理了需求,还是有很多需要改进的地方。首先,扩展性很差——若要添加一个求余的需求,除了改源代码旗本没其他办法了,添加一个需求改一次,这样还了得。其次,可读性不行,别看这个程序看上去还比较清晰,要是考虑上异常、"operator"检查,功能变多后等等就不顺眼了。最后,这个类职责不清晰,又要选择策略又要实现策略。

    实现二:使用策略模式

    抽象策略角色(定义了每个策略都有的接口): 

    public interface IStrategy
    {
    public int doAction(int a, int b);
    }

    具体策略角色(实现抽象策略):

    复制代码
    /*实现加法策略*/
    public class AddStrategy implements IStrategy
    {
    @Override
    public int doAction(int a,int b)
    {
    return a+b;
    }
    }
    复制代码
    复制代码
    /*实现除法策略*/
    public class DivStrategy implements IStrategy
    {
    @Override
    public int doAction(int a, int b)
    {
    return a/b;
    }
    }
    复制代码
    复制代码
    /*实现乘法策略*/
    public class MultiStrategy implements IStrategy
    {
    @Override
    public int doAction(int a, int b)
    {
    return a*b;
    }
    }
    复制代码
    复制代码
    /*实现减法策略*/
    public class SubStrategy implements IStrategy
    {
    @Override
    public int doAction(int a, int b)
    {
    return a-b;
    }
    }
    复制代码

    封装角色:

    复制代码
    public class StrategyContext
    {
    private IStrategy strategy = null;

    public StrategyContext(IStrategy strategy)
    {
    this.strategy = strategy;
    }

    public void replaceStrategy(IStrategy strategy)
    {
    this.strategy = strategy;
    }

    public int doAction(int a,int b)
    {
    return strategy.doAction(a, b);
    }
    }
    复制代码

    场景类:

    复制代码
    public class Client
    {
    public static void main(String[] args)
    {
    /*计算加法,策略模式自身缺点,必须知道具体策略(自己new出来AddStrategy对象)*/
    StrategyContext context = new StrategyContext(new AddStrategy());
    int result = context.doAction(2, 2);

    System.out.println("result : "+result);
    }
    }
    复制代码

      这是按照常规的策略模式实现加减乘除功能的。这样的实现基本上解决了第一种实现方式的缺点。增加一个功能,只需要实现接口 "IStrategy",扩展非常简单便捷。if判断语句消失了,可读性大大提高。每个类的职责现在更清晰了。尽管如此,这个实现还是有一个非常大缺点,这个缺点是该模式自身的缺点,就是调用者必须知道具体策略(这个缺点可以使用混合模式解决)。
    实现三:枚举策略模式

    复制代码
    enum EnumStrategy
    {
    /*加法策略的实现*/
    ADD{
    @Override
    public int execute(int a, int b)
    {
    return a+b;
    }
    },

    /*减法策略的实现*/
    SUB{
    @Override
    public int execute(int a, int b)
    {
    return a-b;
    }
    },

    /*乘法策略的实现*/
    MUL{
    @Override
    public int execute(int a, int b)
    {
    return a*b;
    }
    },

    /*除法策略的实现*/
    DIV{
    @Override
    public int execute(int a, int b)
    {
    return a/b;
    }
    };

    abstract public int execute(int a,int b);
    }
    复制代码

    来看看场景类:

    复制代码
    public class EnumStrategyClient
    {
    public static void main(String[] args)
    {
    System.out.println(EnumStrategy.ADD.execute(2, 2));
    }
    }
    复制代码

      这种变形的策略模式真是太那个了(省略各种赞叹)....太精妙了,不得不佩服那些牛人,这样的实现,让可读性提高到最高点了,一眼就能看明白。连调用都如此简单(你说更看不懂了-_-!!那不是可读性的问题,是你不理解枚举,每一个枚举值其实是这个枚举类型的一个实例,它默认的前缀是public final static的,他其实和类差不多,只不过编译器为我们做了许多事情)。它扩展性没有实现二好,这是受限于enum类型,所以这种变形可以运用在策略不易改变的地方。

  • 相关阅读:
    07java基础知识
    06java基础知识
    我们都忽略了Html5的力量,如果只看成一种技术就大错特错了!
    “微信应用号对行业影响”之一,app开发速来围观
    App开发中甲乙方冲突会闹出啥后果?H5 APP 开发可以改变现状吗
    开发APP不搞清楚这20个问题,必然沦为一场灾难
    H5 App设计者需要注意的21条禁忌
    H5 APP开发必读,20个你不知道的Html5新特征和窍门
    H5 App如此强悍,要降薪的恐怕已不只是iOS程序员
    关于APP,原生和H5开发技术的争论
  • 原文地址:https://www.cnblogs.com/justuntil/p/5514286.html
Copyright © 2020-2023  润新知