1.什么是策略模式
策略模式(Strategy Pattern)也叫做政策模式(Policy Pattern)这种类型的设计模式属于行为型模式
定义一组 算法,将每个算法都封装起来,并且使它们之间可以互换。
自己的理解 做事情 不同情况的处理
引入<<设计模式之禅>>中的例子 刘备江东娶妻 赵云使用诸葛亮三条锦囊妙计
例子1
public class StrategyPattern { static class ZhaoYun { //赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 public static void main(String[] args) { Context context; System.out.println("---拆第一个---"); context = new Context(new BackDoor()); context.operate(); System.out.println("---拆第二个了---"); context = new Context(new GivenGreenLight()); context.operate(); System.out.println("---拆第三个---"); context = new Context(new BlockEnemy()); context.operate(); } } /** * 妙计 策略接口 */ interface IStrategy { public void operate(); } /** * 找乔国老走后门 具体策略类 策略接口子类 */ static class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找乔国老帮忙,让吴国太给孙权施加压力"); } } /** * 求吴国太开绿灯 具体策略类 策略接口子类 */ static class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吴国太开绿灯,放行!"); } } /** * 孙夫人断后 具体策略类 策略接口子类 */ static class BlockEnemy implements IStrategy { @Override public void operate() { System.out.println("孙夫人断后,挡住追兵"); } } /** * 锦囊 环境类 策略执行入口 */ static class Context { private IStrategy straegy; public Context(IStrategy strategy) { this.straegy = strategy; } public void operate() { this.straegy.operate(); } } }
结果如下
调用不同策略就对不同情况进行处理
做事情会有很多情况 不同情况会有不同的处理
比如说想要去旅行 那么旅行要选择那种交通方式呢 飞机 高铁 火车 自家 都行
例子2
public class StrategyPattern2 { public static void main(String[] args) { //模拟客户端调用 选择不同策略 使用不同的旅行方式 GoTravel airplane = new GoTravel(new Airplane()); System.out.println("旅行方式" + airplane.tool()); GoTravel car = new GoTravel(new Car()); System.out.println("旅行方式" + car.tool()); GoTravel highTrain = new GoTravel(new HignTrain()); System.out.println("旅行方式" + highTrain.tool()); } /** * 策略接口 想去旅行 */ interface Travel { public String tool(); } /*** * 环境类 具体执行策略入口 */ static class GoTravel { private Travel travel; public GoTravel(Travel travel) { this.travel = travel; } public String tool() { return travel.tool(); } } /*** * 具体策略类 策略接口子类 */ static class Car implements Travel { @Override public String tool() { return "开车"; } } /*** * 具体策略类 策略接口子类 */ static class HignTrain implements Travel { @Override public String tool() { return "坐高铁"; } } /*** * 具体策略类 策略接口子类 */ static class Airplane implements Travel { @Override public String tool() { return "坐飞机"; } } }
结果如下
2.为什么要用策略模式
使用了策略模式
1.减少大量的if-else语句,可自动切换不同的实现
2.扩展性强 添加策略即添加具体策略实现类
商家对不同客户会执行不同价格 新用户 老用户 VIP用户
例子3
public class PriceManagement { public static void main(String[] args) { BigDecimal price = getPrice(new BigDecimal("10"), "新客户"); System.out.println("price = " + price); BigDecimal price2 = getPrice(new BigDecimal("10"), "老客户"); System.out.println("price2 = " + price2); BigDecimal price3 = getPrice(new BigDecimal("10"), "VIP客户"); System.out.println("price3 = " + price3); } public static BigDecimal getPrice(BigDecimal price , String customType){ if ("新客户".equals(customType)) { System.out.println("抱歉!新客户没有折扣!"); return price; }else if ("老客户".equals(customType)) { System.out.println("恭喜你!老客户打9折!"); price = price.multiply(new BigDecimal("0.9")) .setScale(2,BigDecimal.ROUND_HALF_UP); return price; }else if("VIP客户".equals(customType)){ System.out.println("恭喜你!VIP客户打8折!"); price = price.multiply(new BigDecimal("0.8")) .setScale(2,BigDecimal.ROUND_HALF_UP); return price; } //其他人员都是原价 return price; } }
结果如下
问题 1
getPrice方法 对于不同用户执行不同的方法 可以抽离出来
修改例子3 如下
public class PriceManagementImprove { public static void main(String[] args) { BigDecimal price = getPrice(new BigDecimal("10"), "新客户"); System.out.println("price = " + price); BigDecimal price2 = getPrice(new BigDecimal("10"), "老客户"); System.out.println("price2 = " + price2); BigDecimal price3 = getPrice(new BigDecimal("10"), "VIP客户"); System.out.println("price3 = " + price3); } public static BigDecimal getPrice(BigDecimal price, String customType){ if ("新客户".equals(customType)) { return checkNewCustomer(price); }else if ("老客户".equals(customType)) { return checkOldCustomer(price); }else if("VIP客户".equals(customType)){ return checkVIPCustomer(price); } //其他人员都是原价 return price; } /** * 对VIP客户的报价算法 * @param price 原价 * @return 折后价 */ private static BigDecimal checkVIPCustomer(BigDecimal price) { System.out.println("恭喜!VIP客户打8折"); price = price.multiply(new BigDecimal(0.8)) .setScale(2,BigDecimal.ROUND_HALF_UP); return price; } /** * 对老客户的报价算法 * @param price 原价 * @return 折后价 */ private static BigDecimal checkOldCustomer(BigDecimal price) { System.out.println("恭喜!老客户打9折"); price = price.multiply(new BigDecimal(0.9)) .setScale(2,BigDecimal.ROUND_HALF_UP); return price; } /** * 对新客户的报价算法 * @param price 原价 * @return 折后价 */ private static BigDecimal checkNewCustomer(BigDecimal price) { System.out.println("抱歉!新客户没有折扣!"); return price; } }
结果如下
问题 2
代码仍然有if..else多分支判断 如果价格情况更多 就需要更多else分支
修改例子3 如下 使用策略模式 并增加新的MVP客户
public class StrategyPattern3 { public static void main(String[] args) { //1.创建老客户的价格策略 PriceStrategy oldStrategy = new OldCustomerStrategy(); //2.创建环境类,并设置具体的报价策略 PriceContext context = new PriceContext(oldStrategy); //3.调用环境类的方法 BigDecimal price = context.getPrice(new BigDecimal(100)); System.out.println("折扣价为:" +price); //新增MVP PriceStrategy mvpStrategy = new MVPCustomerStrategy(); PriceContext mvpContext = new PriceContext(mvpStrategy); BigDecimal mvpPrice = mvpContext.getPrice(new BigDecimal(100)); System.out.println("MVP折扣价为:" +mvpPrice); } /** * 策略接口 价格策略 */ interface PriceStrategy { BigDecimal getPrice(BigDecimal price); } /*** * 环境类 具体执行策略入口 */ static class PriceContext { //持有一个具体的价格策略 private PriceStrategy priceStrategy; //注入价格策略 public PriceContext(PriceStrategy priceStrategy){ this.priceStrategy = priceStrategy; } //回调具体价格策略的方法 public BigDecimal getPrice(BigDecimal price){ return priceStrategy.getPrice(price); } } /*** * 具体策略类 策略接口子类 新客户价格 */ static class NewCustomerStrategy implements PriceStrategy { @Override public BigDecimal getPrice(BigDecimal price) { System.out.println("抱歉!新客户没有折扣!"); return price; } } /*** * 具体策略类 策略接口子类 老客户价格 */ static class OldCustomerStrategy implements PriceStrategy { @Override public BigDecimal getPrice(BigDecimal price) { System.out.println("恭喜!老客户打9折"); price = price.multiply(new BigDecimal(0.9)) .setScale(2, BigDecimal.ROUND_HALF_UP); return price; } } /*** * 具体策略类 策略接口子类 VIP客户价格 */ static class VIPCustomerStrategy implements PriceStrategy { @Override public BigDecimal getPrice(BigDecimal price) { System.out.println("恭喜!VIP客户享有8折优惠!"); price = price.multiply(new BigDecimal(0.8)) .setScale(2, BigDecimal.ROUND_HALF_UP); return price; } } /*** * 具体策略类 策略接口子类 新增MVP */ static class MVPCustomerStrategy implements PriceStrategy { @Override public BigDecimal getPrice(BigDecimal price) { System.out.println("哇偶!MVP客户享受7折优惠!!!"); price = price.multiply(new BigDecimal(0.7)) .setScale(2,BigDecimal.ROUND_HALF_UP); return price; } } }
调用老用户策略 MVP策略
结果如下
3.怎么使用策略模式
两个数加减法
例子4
public class Calculator { //加符号 private final static String ADD = "+"; //减符号 private final static String SUB = "-"; //加法运算 private int add(int a, int b) { return a + b; } //减法运算 private int sub(int a, int b) { return a - b; } public int exec(int a, int b, String operator) { int result = 0; if (operator.equals(ADD)) { result = this.add(a, b); } else if (operator.equals(SUB)) { result = this.sub(a, b); } return result; } }
例子4 简化写法
public class Calculator2 { //加符号 private final static String ADD = "+"; // 减符号 private final static String SUB = "-"; public int exec(int a, int b, String operator) { return operator.equals(ADD) ? a + b : a - b; } }
测试
结果如下
例子4 使用策略模式
public class StrategyPattern4 { public static void main(String[] args) { Calculator add = new Add(); int result = add.exec(3, 6); System.out.println("result = " + result); Calculator sub = new Sub(); int result2 = sub.exec(3, 6); System.out.println("result2 = " + result2); } interface Calculator { public int exec(int a, int b); } class Context { private Calculator cal; public Context(Calculator cal) { this.cal = cal; } public int exec(int a, int b, String symbol) { return this.cal.exec(a, b); } } public static class Add implements Calculator { //加法运算 @Override public int exec(int a, int b) { return a + b; } } public static class Sub implements Calculator { //减法运算 @Override public int exec(int a, int b) { return a - b; } } }
测试
结果如下
例子4 使用策略枚举 写法更简练 调用清楚
/*** *功能描述 策略枚举 */ public enum Calculator3 { //加法运算 ADD("+") { @Override public int exec(int a, int b) { return a + b; } }, //减法运算 SUB("-") { @Override public int exec(int a, int b) { return a - b; } }; String value = ""; //定义成员值类型 private Calculator3(String value) { this.value = value; } //获得枚举成员的值 public String getValue() { return this.value; } //声明一个抽象方法 public abstract int exec(int a, int b); }
测试
结果如下
测试类
public class client { public static void main(String[] args) { System.out.println("运行结果为:=" + new Calculator().exec(3,6,"+")); System.out.println("运行结果为:=" + new Calculator().exec(3,6,"-")); System.out.println("运行结果为:=" + new Calculator2().exec(3,6,"+")); System.out.println("运行结果为:=" + new Calculator2().exec(3,6,"-")); System.out.println("运行结果为:=" + Calculator3.ADD.exec(3, 6)); System.out.println("运行结果为:=" + Calculator3.SUB.exec(3, 6)); } }