策略模式是一种定义一系列算法的方法,这些算法完成的都是相同的工作,只是实现不同。它可以用相同的方法来调用这些算法,减少了算法类和使用它们的类之间的耦合。而且,策略模式会简化单元测试,因为每个算法有自己的类,可以通过自己的接口进行单元测试。
现在我们来开发一个商场收银程序,商场经常会有促销活动,比如打折,比如满减,比如积分等等。这些其实都是一些算法,这些算法完成的都是同样的事情,就是通过给定的原价,来计算出最终的价格。那么我们就可以用策略模式来实现这个程序。
首先我们需要有一个父类,来抽象出这些算法。
public abstract class CashSuper {
public abstract double acceptCash(double money);
}
这个父类定义了一个抽象方法,接收原价,返回最终的价格。
下面我们要定义几种算法,来实现acceptCash方法。
原价算法
public class CashNormal extends CashSuper{
public double acceptCash(double money){
return money;
}
}
打折算法
public class CashRebeat extends CashSuper {
private double rebate = 1;
public CashRebeat(double rebeat){
this.rebeat = rebeat;
}
public double acceptCash(double money){
return rebeat * money;
}
}
满减算法
public class CashReturn extends CashSuper {
private double condition = 0;
private double moneyReturn = 0;
public CashReturn (double condition,double moneyReturn) {
this.condition = condition;
this.moneyReturn = moneyReturn;
}
public double acceptCash(double money){
return money - Math.floor(money / condition) * moneyReturn;
}
}
然后我们需要定义一个上下文类,维护一个对策略对象的引用
public class Context {
private CashSuper cashSuper;
public Context (CashSuper cashSuper) {
this.cashSuper = cashSuper;
}
public double getResult(double money) {
return cashSuper.acceptCash(money);
}
}
当我们要用的时候,就可以传给Context不同的对象,来实现不同的策略。
比如
private Context context;
switch(type) {
case "原价":
context = new Context(new CashNormal());
break;
case "打八折" :
context = new Context(new CashRebeat(0.8));
braek;
}
System.out.println(context.getResult(money));
但这样会将选择算法的任务交给调用方,耦合度很高。我们希望调用方只关心自己的打折方式、原价,最终价格,不需要参与算法的选择。所以我们可以将简单工厂模式与策略模式结合起来。用简单工厂来生产策略。
重写上下文类
public class Context {
private CashSuper cashSuper;
public Context (String type) {
switch(type) {
case "原价":
cashSuper = new CashNormal();
break;
case "打八折" :
cashSuper = new CashRebeat(0.8));
braek;
}
}
public double getResult(double money) {
return cashSuper.acceptCash(money);
}
}
这个时候调用方就不需要考虑生成什么策略了,只需要将参数传给上下文对象,由上下文对象自动生产出算法对象即可。
private Context context;
context = new Context("打八折");
System.out.println(context.getResult(money));
可以看到调用方只和Context对象进行了交互,实现了解耦。如果这里我们使用简单工厂来实现呢?
调用方需要有一个父类的引用,还需要调用简单工厂来生产具体算法类。所以用简单工厂会和2个类进行交互。所以在这个例子中,策略模式减少了耦合。
相关demo可以参考我的gitee仓库
https://gitee.com/akitsuki-kouzou/DesignPatternDemo