意思:指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。。
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例:
- 商场促销方式,打折、满减等。
- 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
- JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
策略模式的实现
1. 上下文类
首先声明一个CashSuper对象,通过构造方法,传入具体的收费策略,getResult()方法的功能为根据收费策略的不同获得计算结果。
public class CashContext {
private CashSuper cashSuper;
public CashContext(CashSuper cashSuper) {
this.cashSuper = cashSuper;
}
public double getResult(double money) {
return cashSuper.acceptCash(money);
}
}
- 现金收费抽象类
策略类,为抽象类,抽象出收费的方法供子类实现。
public abstract class CashSuper {
public abstract double acceptCash(double money);
}
- 正常收费子类
没有任何活动的情况,正常收费,返回原价。
public class CashNormal extends CashSuper {
@Override
public double acceptCash(double money) {
return money;
}
}
- 打折收费子类
打折活动,根据折扣返回打折后的价格。
public class CashRebate extends CashSuper {
private double moneyRebate = 1; //折扣
public CashRebate(double moneyRebate) {
this.moneyRebate = moneyRebate;
}
@Override
public double acceptCash(double money) {
return money * moneyRebate;
}
}
5. 返利收费子类
返利活动,输入返利条件和返利值,比如满300返100,moneyCoditation为300,moneyReturn为100。
result = money - Math.floor(money / moneyConditation) * moneyReturn; 的意思为,如果当前金额大于等于返利条件,则使用当前金额减去返利值。
public class CashReturn extends CashSuper {
private double moneyConditation = 0.0; //返利条件
private double moneyReturn = 0.0d; //返利值
public CashReturn(double moneyConditation, double moneyReturn) {
this.moneyConditation = moneyConditation;
this.moneyReturn = moneyReturn;
}
@Override
public double acceptCash(double money) {
double result = money;
if (money >= moneyConditation) {
result = money - Math.floor(money / moneyConditation) * moneyReturn;
}
return result;
}
}
- Client客户端
下面写一个简单的程序测试一下上方编写的代码。
public class Client {
public static void main(String[] args) {
CashContext cashContext = null;
Scanner scanner = new Scanner(System.in);
System.out.print("请输入打折方式(1/2/3):");
int in = scanner.nextInt();
String type = "";
switch (in) {
case 1:
cashContext = new CashContext(new CashNormal());
type += "正常收费";
break;
case 2:
cashContext = new CashContext(new CashReturn(300, 100));
type += "满300返100";
break;
case 3:
cashContext = new CashContext(new CashRebate(0.8));
type += "打8折";
break;
default:
System.out.println("请输入1/2/3");
break;
}
double totalPrices = 0;
System.out.print("请输入单价:");
double price = scanner.nextDouble();
System.out.print("请输入数量:");
double num = scanner.nextDouble();
totalPrices = cashContext.getResult(price * num);
System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices);
scanner.close();
}
}