Skip to content

策略模式

ZHI-XINHUA edited this page Jan 11, 2019 · 1 revision

策略模式

策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

一、策略模式的结构

策略模式又称政策模式,结构图如下: image

角色:

  • 环境(Context)角色:持有一个Strategy类的引用。
  • 抽象策略(Strategy)角色:一个抽象角色,通常由一个接口或抽象类(可以多继承)实现。次角色给出所有具体策略类所需的接口。
  • 具体策略(ConcreteStrategy)角色:包装类相关的算法或行为。

二、策略模式的栗子实现

需求:整数计算操作:加减乘...

uml图如下: image

(1)计算抽象类(抽象策略角色)

package com.strategy;

/**
 * 计算抽象类(抽象策略角色)
 */
public abstract class Calculator {

    public abstract int calculate(int num1,int num2);
}

(2)加减乘具体策略类(具体策略角色) 加法:

package com.strategy;

/**
 * 加法计算。(具体策略角色:包装了相关的算法或行为)
 */
public class AddCalculator extends Calculator {

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

}

减法:

package com.strategy;
/**
 * 减法计算。(具体策略角色:包装了相关的算法或行为)
 */
public class SubCalculator extends Calculator {
    @Override
    public int calculate(int num1, int num2) {
        return num1 - num2;
    }
}

乘法:

package com.strategy;
/**
 * 乘法计算。(具体策略角色:包装了相关的算法或行为)
 */
public class MultiCalculator extends Calculator {
    @Override
    public int calculate(int num1, int num2) {
        return num1 * num2;
    }
}

(3)context类管理策略,根据客户端传入的具体策略执行改策略方法(环境角色)

package com.strategy;

/**
 * 环境角色:持有一个Strategy类的引用
 */
public class Context {
    private Calculator calculator;

    public Context(Calculator calculator){
        this.calculator = calculator;
    }

    public int executeCalculate(int num1,int num2){
        return calculator.calculate(num1,num2);
    }
}

(4)测试

package com.strategy;
public class ClientMain {
    public static void main(String[] args) {
        //加法计算
        Context c1 = new Context(new AddCalculator());
        int result1 = c1.executeCalculate(2,3);
        System.out.println(result1);

        //减法计算
        Context c2 = new Context(new SubCalculator());
        int result2= c1.executeCalculate(2,3);
        System.out.println(result2);

        //乘法计算
        Context c3 = new Context(new MultiCalculator());
        int result3 = c1.executeCalculate(2,3);
        System.out.println(result3);

    }
}

三、在什么情况喜爱应当使用策略模式

  1. 如果在一个系统里面许多类,它们直接的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  2. 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换而言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。
  3. 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂和只与算法有关的数据。
  4. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象的概念。

四、策略模式的优点和缺点

优点

  1. 策略模式提供类管理相关的算法族的方法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
  2. 策略模式提供类可以替换继承关系的方法。继承可以处理多种算法或行为。如果不是使用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
  3. 使用策略模式可以避免使用多重条件转移语句。

缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
  2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

五、java里的使用

后续补充....