天天看点

策略模式(政策模式) 策略枚举策略模式策略模式定义策略模式实现计算器策略枚举策略模式优点策略模式缺点

策略模式

策略模式定义

Define a familly algorithms, encapsulate each one, and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使他们之间互相转换)。

从以上官方定义分析到策略模式具有三个角色分别是:

  • 封装角色
  • 抽象策略角色(策略接口)
  • 具体策略角色(实现策略接口的类)

策略模式实现计算器

  我们分析一下计算器的简单运算,以加减法为例来划分一下其中的角色,比如 加法:1+1=2,减法1-1=0。这里加法和减法都是一个运算可以理解为两个策略;他们都有计算的功能需要定义一个接口提供统一的运算方法,这个为抽象策略角色;高层实现减价法则为封装角色及将接口放进去,通过接口调用,所以高层不用知道具体是加法还是减法。

因此封装角色起到了承上启下的作用,屏蔽了高层模块对策略、算法的直接访问,封装可能存在的变化。

  下来简单实现计算器加减法的功能:

策略的接口,定义执行的方法:

package design.strategy.c001;

/**
 * 定义策略接口(一组策略)
 * @author yanwenfei
 *
 */
public interface IStrategy {

	//策略需要执行的方法
	public int exec(int a, int b);
}
           

创建具体的策略角色及加法和减法

package design.strategy.c001;

/**
 * 策略A加法
 * @author yanwenfei
 *
 */
public class StrategyADD implements IStrategy {

	@Override
	public int exec(int a, int b) {
		return a+b;
	}

}
           
package design.strategy.c001;

/**
 * 减法策略
 * @author yanwenfei
 *
 */
public class StrategySub implements IStrategy {

	@Override
	public int exec(int a, int b) {
		return a - b;
	}

}
           

封装角色。这里通过构造方法将具体的策略传入高层,而高层不用知道具体是哪种策略,只需要调用抽象策略的方法即可

package design.strategy.c001;

/**
 * 策略分装类
 * @author yanwenfei
 */
public class Calculator {

	private IStrategy strategy;
	
	//切换策略
	public Calculator(IStrategy strategy) {
		this.strategy = strategy;
	}

	//执行策略方法
	public int exec(int a, int b){
		return strategy.exec(a, b);
	}
}
           

场景类

package design.strategy.c001;

public class TestMain {

	public static void main(String[] args) {

		Calculator calculator = null;
		
		IStrategy streadd = new StrategyADD();//创建加法策略;
	    calculator = new Calculator(streadd);//切换策略
		int add = calculator.exec(20, 30);
		System.out.println("20 + 30 = " + add);
		
		IStrategy stresub = new StrategySub();//创建减法策略;
		calculator = new Calculator(stresub);//切换策略
		int sub = calculator.exec(20, 30);
		System.out.println("20 - 30 = " + sub);
	}

}
           

运算结果:

10 + 30 = 40
10 - 30 = -20
           

以上为策略模式传统的实现方式,肯定很多人能看出来这个策略模式有很多缺点,虽然便于扩展,但是每一个策略都是一个类,这个先不说,下来看一下很牛逼的策略枚举。

策略枚举

我们可以使用枚举在一个类中实现以上所有的功能及三种不同的角色,对不熟悉枚举的小伙伴可以查阅资料,下来看看通过枚举实现策略模式

package design.strategy.c002;
/**
 * 策略枚举
 * @author yanwenfei
 */
public enum Calculator {
	


	ADD("+") {
		@Override
		public int exec(int a, int b) {
			// TODO Auto-generated method stub
			return a+b;
		}
	},
	
	SUB("-") {
		@Override
		public int exec(int a, int b) {
			// TODO Auto-generated method stub
			return a-b;
		}
	};
	
	
	public abstract int exec(int a, int b);
	
	//运算符
	private String value = "";
	
	private Calculator(String value) {
		this.value = value;
	}

	public String getValue() {
		return value;
	}
	
}
           

场景类:

package design.strategy.c002;

public class TestMain {

	public static void main(String[] args) {
		
		int add = Calculator.ADD.exec(10, 30);
		System.out.println("10 + 30 = "+add);
		
		int sub = Calculator.SUB.exec(10, 30);
		System.out.println("10 - 30 = "+sub);
	}
}
           

运算结果:

10 + 30 = 40
10 - 30 = -20
           

这里已经结束了,感觉是不是很爽,简直太爽了,通过枚举的使用,在一个类中就完美的实现了策略模式

在枚举类中,定义的抽象方法就像当时之前的接口,每一个枚举ADD SUB相当是一个具体的实现类(策略角色),而整个枚举类就是策略的分装角色。

策略模式优点

  • 算法可以自由切换(高层屏蔽算法,角色自由切换)
  • 避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
  • 扩展性好(可自由添加取消算法 而不影响整个功能)

策略模式缺点

  • 策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
  • 所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)

继续阅读