大话设计模式—策略模式

Posted May的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大话设计模式—策略模式相关的知识,希望对你有一定的参考价值。

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

大话设计模式中程杰老师给出的定义是这样的:策略模式(Strategy),定义了算法家族,分别封装起来,让它们之间可以互相替换,从模式让算法的变化不会影响到使用算法的用户

面向对象编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类,即区分这些类的只是他们的直接行为;

一个很形象的实例就是商场的收银系统,商场收银时如何促销,用打折还是返利,其实都是一些算法,打一折和打九折只是形式不同,抽象分析出来,所有的打折算法都是一样的,算法本身只是一种实现促销或打折的策略,重要的是这些算法是随时都可能被替换掉的,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维方式。

这里写图片描述

实例解析

我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。类图如下:

这里写图片描述

策略接口:

package com.dfcDemo;

public interface Strategy {

    public int doOperation(int num1,int num2);

}

四个策略实现类:

package com.dfcDemo;

public class StrategySubstract implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }

}
package com.dfcDemo;

public class StrategyAdd implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }

}
package com.dfcDemo;

public class StrategyMulpitly implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        return num1 * num2;
    }

}
package com.dfcDemo;

public class StrategyDivision implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        //此处注重策略模式的应用,只给出简单实现,不考虑除数为0的情况
        return num1 / num2;
    }

}

使用策略的Context类:

package com.dfcDemo;

public class Context {

    private Strategy strategy;

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

    public int executeStrategy(int num1,int num2){
        return strategy.doOperation(num1, num2);
    }
}

测试类:

package com.dfcDemo;

public class TestStrategyDemo {

    public static void main(String[] args) {

        Context contextAdd = new Context(new StrategyAdd());
        System.out.println("6 + 3 = " + contextAdd.executeStrategy(6, 3));

        Context contextSubstract = new Context(new StrategySubstract());
        System.out.println("6 - 3 = " + contextSubstract.executeStrategy(6, 3));

        Context contextMulpitly = new Context(new StrategyMulpitly());
        System.out.println("6 * 3 = " + contextMulpitly.executeStrategy(6, 3));

        Context contextDivision = new Context(new StrategyDivision());
        System.out.println("6 / 3 = " + contextDivision.executeStrategy(6, 3));

    }

}
运行结果:

6 + 3 = 9
6 - 3 = 3
6 * 3 = 18
6 / 3 = 2

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。Strategy类层次为Context定义了一系列的可供重用的算法和行为。当不同的行为堆砌在一个类中的时候,就很难避免使用条件语句来判断选择合适的行为,将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句。

优点:

1、算法可以自由切换。
2、避免使用多重条件判断。
3、扩展性良好。
4、简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景:

1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

策略模式时用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种可能发生的变化。

但是在策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式使用对象,这本身并没有解除客户端需要选择判断的压力,解决这一问题的方法是使用策略模式和简单工厂模式结合,选择具体实现的职责也由策略使用类Context来承担。这就最大化的减轻了客户端的职责。

策略模式和简单工厂模式结合:

改造使用策略模式的Context类使其实现一个简单工厂的功能

package com.dfcDemo;

//将实例化具体策略的过程由客户端转移到具体策略使用类ContextFactory中
public class ContextFactory {

    private Strategy strategy;

    //注意这里传入的参数是一个表示策略类型的字符串,而不是具体的策略对象
    public ContextFactory(String type){
        switch(type){
        case "add":
          StrategyAdd add = new StrategyAdd();
          strategy = add;
          break;
        case "substract":
          StrategySubstract substract = new StrategySubstract();
          strategy = substract;
          break;
        case "multiply":
          StrategyMulpitly mulpitly = new StrategyMulpitly();
          strategy = mulpitly;
          break;
        case "division":
          StrategyDivision division = new StrategyDivision();
          strategy = division;
          break;
    }
    }

    public int executeStrategy(int num1,int num2){
        return strategy.doOperation(num1, num2);
    }
}
//测试方法
public int TestStrategyFactoryDemo(String type) {

    ContextFactory contextFactory = new ContextFactory(type);
    return contextFactory.executeStrategy(6, 3);

}

这样具体策略的使用就与客户端彻底分离了。

以上是关于大话设计模式—策略模式的主要内容,如果未能解决你的问题,请参考以下文章

大话设计模式之策略模式

大话涉及模式Python实现-策略模式

大话设计模式之策略模式

java 之 策略模式(大话设计模式)

大话设计模式------策略模式

大话设计模式——策略模式