设计模式之12策略模式(笔记)

1 定义:

1.1 定义:Define a family of algorithms, encapsulate each one, and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换)

1.2 通用类图:

角色解说:

Context封装角色:也叫上下文角色,屏蔽高层模块对策略、算法的直接访问,封装可能的变化。

Stategy抽象策略角色:策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。

ConcreteStrategy具体策略角色:实现抽象策略中的操作,该类含有具体的算法。

1.3 通用代码:

	public interface Strategy {
		// 策略模式的运算法则
		public void doSomething();
	}

	public class ConcreteStrategy1 implements Strategy {
		public void doSomething() {
			System.out.println("具体策略1的运算法则");
		}
	}

	public class ConcreteStrategy2 implements Strategy {
		public void doSomething() {
			System.out.println("具体策略2的运算法则");
		}
	}

	public class Context {
		// 抽象策略
		private Strategy strategy = null;

		// 构造函数设置具体策略
		public Context(Strategy _strategy) {
			this.strategy = _strategy;
		}

		// 封装后的策略方法
		public void doAnythinig() {
			this.strategy.doSomething();
		}
	}

	public class Client {
		public static void main(String[] args) {
			// 声明出一个具体的策略
			Strategy strategy = new ConcreteStrategy1();
			// 声明出上下文对象
			Context context = new Context(strategy);
			// 执行封装后的方法
			context.doAnythinig();
		}
	}

针对不同的算法,直接根据算法new一个新的Context,即可,不用做别的。

2 优点

2.1 算法可以自由切换;

2.2 避免多重条件判断:策略模式中,可以由其他模块决定采用何种策略,策略家族对外提供的访问接口就是封装类(上下文),简化了操作,同时避免了条件语句判断;

2.3 扩展性良好:添加策略时,只要实现接口就可以了,其他都不用修改,OCP

3 缺点

3.1 策略类数量增多:但复用的可能性很小;

3.2 所有的策略类都需要对外暴露:上层模块必须知道有哪些策略,然后才能决定使用哪一个策略,这与LOW法则相违背(只是想使用一个策略,为什么要了解它呢?)。那要封装类作何?这原是策略模式的一个缺点。可以使用工厂方法模式、代理模式或享元模式(应该是使用这些模式,直接返回一个已封装了某一策略的Context对象)。

4 应用场景

4.1 多个类只有在算法或行为上稍有不同的场景;

4.2 算法需要自由切换的场景:算法的选择由使用者决定,或算法始终在进化。

4.3 需要屏蔽算法规则的场景:我只想记住算法名,给我反馈结果即可。

5 注意事项

一个策略家族的具体策略数量超过4个,则需要考虑混合模式,解决策略类膨胀和对外暴露的问题,否则日后的系统维护太难。

6 扩展

6.1 策略枚举:在枚举里定义抽象方法,并在其内部实现若干实例。(但是扩展性不好,因为它受枚举类型的限制,每个枚举项都是publicfinalstatic的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一般担当不起经常发生变化的角色。)

可以根据3.2,结合7.2例,来由其它模式提供算法的封装。

7 范例(作者原书例)

7.1 策略模式实现加减法:

	interface Calculator {
		public int exec(int a, int b);
	}

	public class Add implements Calculator {
		// 加法运算
		public int exec(int a, int b) {
			return a + b;
		}
	}

	public class Sub implements Calculator {
		// 减法
		public int exec(int a, int b) {
			return a - b;
		}
	}

	public class Context {
		private Calculator cal = null;

		public Context(Calculator _cal) {
			this.cal = _cal;
		}

		public int exec(int a, int b, String symbol) {
			return this.cal.exec(a, b);
		}
	}

	public class Client {
		// 加符号
		public final static String ADD_SYMBOL = "+";
		// 减符号
		public final static String SUB_SYMBOL = "-";

		public static void main(String[] args) {
			// 输入的两个参数是数字
			int a = Integer.parseInt(args[0]);
			String symbol = args[1]; // 符号
			int b = Integer.parseInt(args[2]);
			System.out.println("输入的参数为:" + Arrays.toString(args));
			// 上下文
			Context context = null;
			// 判断初始化哪一个策略
			if (symbol.equals(ADD_SYMBOL)) {
				context = new Context(new Add());
			} else if (symbol.equals(SUB_SYMBOL)) {
				context = new Context(new Sub());
			}
			System.out.println("运行结果为:" + a + symbol + b + "="
					+ context.exec(a, b, symbol));
		}
	}

7.2 枚举策略实现加减法:

	public enum Calculator {
		//加法运算
		ADD("+"){
			public int exec(int a,int b){
				return a+b;
			}
		},
		//减法运算
		SUB("-"){
			public int exec(int a,int b){
				return a - b;
			}
		};
		
		String value = "";
		//定义成员值类型
		private Calculator(String _value){
			this.value = _value;
		}
		//获得枚举成员的值
		public String getValue(){
			return this.value;
		}
		//声明一个抽象函数
		public abstract int exec(int a,int b);
		}
	
		import java.util.Arrays;
		/**
		* @author cbf4Life [email protected]
		* I'm glad to share my knowledge with you all.
		*/
		public class Client {
			public static void main(String[] args) {
				//输入的两个参数是数字
				int a = Integer.parseInt(args[0]);
				String symbol = args[1]; //符号
				int b = Integer.parseInt(args[2]);
				System.out.println("输入的参数为:"+Arrays.toString(args));
				System.out.println("运行结果为:"+a + symbol + b + "=" + Calculator.ADD.exec(a, b));
			}
		}

你可能感兴趣的:(设计模式之12策略模式(笔记))