策略模式属于对象的行为模式,其用意是针对某一组算法,将每一个算法封装到具有公共接口的独立实现类中,从而使它们可以相互替代,并可在不影响客户端的情况下发生变化。
下面以超市收银时,有多种收费策略来对策略模式进行举例:
参与角色:
- 抽象策略
- 具体策略
- 配置策略
抽象策略:
/**
* 抽象收费策略
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public abstract class CashSuper {
/**
* 抽象收费方法
* @param money
*/
public abstract double charge(double money);
}
三个具体的策略
/**
* 具体的正常收费策略
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class NormalChargeStrategy extends CashSuper{
/**
* 具体收费方法
* @return
*/
@Override
public double charge(double money) {
return money;
}
}
/**
* 具体折扣收费策略
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class DiscountChargeStrategy extends CashSuper{
// 折扣[0,1]
private double ratio;
public DiscountChargeStrategy(double ratio){
this.ratio = ratio;
}
/**
* 具体收费方法
* @return
*/
@Override
public double charge(double money) {
return money * ratio;
}
}
/**
* 具体满减收费策略
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class FullChargeReductionStrategy extends CashSuper{
// 满减条件
private double condition;
// 满减金额
private double reduce;
public FullChargeReductionStrategy(double condition, double reduce){
this.condition = condition;
this.reduce = reduce;
}
/**
* 具体收费方法
* @return
*/
@Override
public double charge(double money) {
return money >= condition ? money - reduce : money;
}
}
配置策略:
/**
* 配置策略
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class CashContext {
private CashSuper cashSuper;
public CashContext(CashSuper cashSuper){
this.cashSuper = cashSuper;
}
/**
* 收费结果
* @param money
* @return
*/
public double getResult(double money){
return cashSuper.charge(money);
}
}
客户端测试:
/**
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class Main {
/**
* 商品收银系统
* 1.正常收费
* 2.打折收费
* 3.满减收费
* 收银系统有多种收费策略,请使用策略模式来实现代码
* @param args
*/
public static void main(String[] args) {
/**
* 策略模式实现:
* 1.抽象策略 CashSuper
* 2.具体策略 NormalChargeStrategy、DiscountChargeStrategy、FullChargeReductionStrategy...
* 3.配置策略 CashContext
*/
double money = 300;
CashContext cash;
cash = new CashContext(new NormalChargeStrategy());
double r1 = cash.getResult(money);
System.out.println(money + "->正常收费:" + r1);
System.out.println("=========================");
cash = new CashContext(new DiscountChargeStrategy(0.8));
double r2 = cash.getResult(money);
System.out.println(money + "->打8折:" + r2);
System.out.println("=========================");
cash = new CashContext(new FullChargeReductionStrategy(300, 100));
double r3 = cash.getResult(money);
System.out.println(money + "->满300减100:" + r3);
}
}
策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
缺点:
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
策略模式中选择具体的策略由客户端对象承担,并转给策略模式的Context。没有减轻客户端的选择压力,可以与简单工厂结合,将选择的权利也交给Context,从而减轻客户端选择的压力。
/**
* 配置策略 + 简单工厂
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class CashContext {
private CashSuper cashSuper;
public CashContext(String strategy){
switch (strategy){
case "正常收费":
cashSuper = new NormalChargeStrategy();
break;
case "打8折":
cashSuper = new DiscountChargeStrategy(0.8);
break;
case "满300减100":
cashSuper = new FullChargeReductionStrategy(300, 100);
break;
default:
break;
}
}
/**
* 收费结果
* @param money
* @return
*/
public double getResult(double money){
return cashSuper.charge(money);
}
}
/**
* 策略模式 + 简单工厂
* @author Linging
* @version 1.0.0
* @since 1.0
*/
public class Main {
public static void main(String[] args) {
CashContext cash;
double money = 300;
cash = new CashContext("正常收费");
double r1 = cash.getResult(money);
System.out.println(money + "->正常收费:" + r1);
System.out.println("=========================");
cash = new CashContext("打8折");
double r2 = cash.getResult(money);
System.out.println(money + "->打8折:" + r2);
System.out.println("=========================");
cash = new CashContext("满300减100");
double r3 = cash.getResult(money);
System.out.println(money + "->满300减100:" + r3);
}
}