策略模式 -- 其实就是封装了不同算法的一种方式,让客户端代码只需要跟那个策略类进行交互,而不需要进行再与底层的其他什么类进行交互,耦合度大大的降低
情景 :写一个商场打折促销的收费系统,促销方式有 : 打0.8折, 满500减200, 还有正常收费
思路 :因为促销的方式分了几种,但是目的都是一样的,就是算最终的收费金额,所以,当方式不同,但目的一样时,就可以用工厂方法,
上代码
首先先定义一个父类来总结几个子类的接口,这个时候,就可以用抽象类,因为,这个类是几个具体方式的抽象出来的总结,不需要实例化
package strategicMode; /* 对收钱的概念的抽象 * */ public abstract class CashSuper { public abstract double getResult(double money); }
然后是那几个具体方式的实现
package strategicMode; /* * 正常收费区 * */ public class CashNormal extends CashSuper{ public CashNormal(){ } @Override public double getResult(double money) { return money; } }
package strategicMode; /* * 折扣区 * */ public class CashRebate extends CashSuper{ private double rebate; private double result; public CashRebate(double rebate) { this.rebate = rebate; } public double getResult(double money) { result = money*rebate; return result; } }
package strategicMode; /* * 返利区 * */ public class CashReturn extends CashSuper{ private double minMon; private double returnMon; private double result; public CashReturn(double minMon, double returnMon) { this.minMon = minMon; this.returnMon = returnMon; } @Override public double getResult(double money) { if(money > minMon){ result = money - returnMon; } return result; } }
好了,下面就是套路了,写个工厂类判别什么时候调用哪个促销收费方式
package strategicMode; /* * 促销方式的工厂方法 * */ public class CashWayFactory { CashSuper cashWay; public CashSuper getCashAcceptWay(String cashAcceptWay){ switch(cashAcceptWay){ case "打八折": cashWay = new CashRebate(0.8); break; case "正常收费" : cashWay = new CashNormal(); break; case "满500返200" : cashWay = new CashReturn(500, 200); break; } return cashWay; } }
客户端代码
package strategicMode; import java.util.Scanner; import org.junit.Test; /* * 客户端代码 * */ public class ClientCode { CashWayFactory cashWayFactoy = new CashWayFactory(); CashSuper cashWay; @Test public void testCashWay(){ System.out.println("请输入你的收费方式(打八折, 正常收费, 满500返200)"); Scanner in = new Scanner(System.in); String cashAcceptWay = in.next(); System.out.println("请输入总费用:"); double money = in.nextDouble(); cashWay = cashWayFactoy.getCashAcceptWay(cashAcceptWay); double result = cashWay.getResult(money); System.out.println("你需要交的总费用: "+result); } }
但是上面的代码灵活性不是很高,当我需求改变了,要加一些其他的促销方式时,就还是要在工厂里面进行改动和维护,导致整个代码需要重新编译部署,包括了客户端的代码,引用客户端的代码是直接和工厂方法进行了交互的,所以这样来说还是非常鸡肋的。于是就有了策略方式
策略模式 就是一种可以封装不同算法的方式,最终得到一个不同算法,但目的一样的值,简单明了的就是封装了变化性
package strategicMode; /* * 维护对CashSuper对象的引用 * */ public class StrategeContext { CashSuper cashWay; // 策略模式与工厂相结合 public StrategeContext(String cashWayString) { switch(cashWayString){ case "打八折": cashWay = new CashRebate(0.8);break; case "正常收费" : cashWay = new CashNormal();break; case "满500返200" : cashWay = new CashReturn(500, 200);break; } } // 现在我要的需求是 : 客户端的代码只需要调用这个方法就可以得到相应的结果了 public double cashAcceptWay(double money){ return cashWay.getResult(money); } }
上面的策略类就是把所有不同的算法方式,都封装到一起了,现在只是需要得到一个值返回给客户端,而客户端的代码也会变得十分简洁
package strategicMode; import java.util.Scanner; import org.junit.Test; /* * 拥有 * */ public class ClientCode2_0 { StrategeContext context; @Test public void testCashWay(){ System.out.println("请输入总共花费:"); Scanner in = new Scanner(System.in); double cash = in.nextDouble(); System.out.println("请输入你的收费方式(打八折, 正常收费, 满500返200)"); String cashWayString = in.next(); context = new StrategeContext(cashWayString); System.out.println("你应该收取的费用是 : "+context.cashAcceptWay(cash)); } }
可以看到客户端只需要有一个策略类就能得到相应的结果,而不需要再跟工厂和促销方式这些底层的东西打交道了。。。就相当于,现在已经从经理直接升级为了ceo了,我只需要一个策略,其余的让下面的人去做,我不需要管,而策略类就是部署下面的人去做的中间商,可以看作经理。但是这个代码终归是不完整的,因为还有一个重要的问题没有解决,就是,我每次新加入一个需求促销方式,都要去策略类哪里部署,让他去做,这也是很麻烦的,所以就会引入反射这个方式,后面的blog我会继续提到。