定义一组算法,将每个算法都封装起来,使它们之间可以互换。
策略模式和代理模式差别就是策略模式的封装角色和被封装的策略类不用是同一个接口。如果是同一个接口那就是代理模式了。
策略模式代替if-else,传什么类型过去,就执行什么策略。
一、赵云使用三个锦囊
1. 妙计接口
public interface IStrategy {
//每个妙计都是一个可执行的算法
public void operate();
}
2. 乔国老开后门
public class BackDoor implements IStrategy{
@Override
public void operate() {
System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
}
}
3. 吴国太开绿灯
public class GivenGreenLight implements IStrategy{
@Override
public void operate() {
System.out.println("求吴国太开绿灯,放行!");
}
}
4. 孙夫人断后
public class BlockEnemy implements IStrategy{
@Override
public void operate() {
System.out.println("孙夫人断后,挡住追兵");
}
}
5. 锦囊
public class Context {
//构造函数,你要使用哪个妙计
private IStrategy strategy;
public Context(IStrategy strategy) {
this.strategy = strategy;
}
//使用计谋了,看我出招了
public void operate(){
this.strategy.operate();
}
}
6. 使用计谋
public class ZhaoYun {
//赵云出场了,他根据诸葛亮给他的交代,依次拆分妙计
public static void main(String[] args) {
Context context;
//刚刚到吴国的时候拆第一个
System.out.println("------刚刚到吴国的时候拆第一个------");
context = new Context(new BackDoor());//拿到妙计
context.operate(); //拆开执行
System.out.println("\n\n\n\n\n\n\n");
//刘备乐不思蜀了,拆第二个
System.out.println("------刘备乐不思蜀了,拆第二个------");
context = new Context(new GivenGreenLight());
context.operate(); //拆行了第二个锦囊
System.out.println("\n\n\n\n\n\n\n");
//孙权的小兵追来了,拆第三个
System.out.println("------孙权的小兵追来了,拆第三个----");
context = new Context(new BlockEnemy());
context.operate();
}
}
二、策略模式的定义定义一组算法,将每个算法都封装起来,使它们之间可以互换。
策略模式和代理模式差别就是策略模式的封装角色和被封装的策略类不用是同一个接口。如果是同一个接口那就是代理模式了。
1. 抽象的策略角色
public interface Strategy {
//策略模式的运算法则
public void doSomething();
}
2. 具体策略角色
public class ConcreteStrategy1 implements Strategy{
@Override
public void doSomething() {
System.out.println("具体策略1的运算法则");
}
}
&
public class ConcreteStrategy2 implements Strategy{
@Override
public void doSomething() {
System.out.println("具体策略2的运算法则");
}
}
3. 封装角色
public class Context {
//抽象策略
private Strategy strategy = null;
//构造函数设置具体策略
public Context(Strategy strategy) {
this.strategy = strategy;
}
//封装后的策略方法
public void doAnythinig(){
this.strategy.doSomething();
}
}
4. 高层模块
public class Client {
public static void main(String[] args) {
//声明一个具体的策略
Strategy strategy = new ConcreteStrategy1();
//声明上下文对象
Context context = new Context(strategy);
//执行封装后的方法
context.doAnythinig();
}
}
三、策略模式的应用
1. 优点
1)保证对外提供“可自由切换“的策略。
2)避免使用多重条件判断
3)扩展性良好
2. 缺点
1)策略类数量增多,每一个策略都是一个类,复用性很小。
2)上层模块必须知道有哪些策略,然后才能决定使用哪一个策略。所以策略模式可以工厂方法模式、代理模式和享元模式
3. 使用场景
1)多个类只有在算法或行为上稍有不同的场景
2)算法需要自由切换的场景
3)需要屏蔽算法 规则的场景
4. 注意
如果具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露的问题。
四、扩展
输入int的a、b,然后输入String的"+"或"-",计算出结果
这里"+"或"-"就可以看成一个策略
------------------------------扩展1 : 普通策略-----------------------------------
1. 引入策略模式
public interface Calculator {
public int exec(int a,int b);
}
2. 上下文
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;
}
}
3. 上下文
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);
}
}
4. 场景类
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));
}
}
------------------------------扩展2 : 枚举策略-----------------------------------1. 策略枚举
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);
}
2. 场景类
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));
}
}