基于渡一教育拓哥策略者设计模式课程讲解,及大佬文章、个人理解。
应用背景:学生去书店买书,根据会员卡等级决定打折比例,不同会员卡等级对应不同的打折策略。
首先,可能会想到如下的解决方案,用数字来表示学生会员卡等级。
package nopattern;
public class Price {
public double getPrice(double goodsPrice,int customerType){
double price=0;
switch (customerType) {
case 0:
//没有会员卡不打折
price = goodsPrice * 1;
break;
case 1:
//普通会员卡打8折
price = goodsPrice * 0.8;
break;
case 2:
//至尊会员卡打5折
price = goodsPrice * 0.5;
break;
default:
//假的会员卡涨价
price = goodsPrice * 1.1;
break;
}
return price;
}
}
分析:代码的可读性不好,数字表示学生会员卡等级,除设计者以外其他人可能无法识别,所以,考虑用静态常量或枚举类型来代替,同时,代码违背了单一原则,所以考虑采用如下代码。
1.静态常量
VipType.java
package nopattern;
public class VipType {
public static final int NO_VIP=0;
public static final int NORMAL_VIP=1;
public static final int EXPENSIVE_VIP=2;
}
Price.java
package nopattern;
public class Price {
public double getPrice(double goodsPrice,int customerType){
double price=0;
switch (customerType) {
case VipType.NO_VIP:
//没有会员卡不打折
price = getPriceForNo_VIP(goodsPrice);
break;
case VipType.NORMAL_VIP:
//普通会员卡打8折
price = getPriceForNORMAL_VIP(goodsPrice);
break;
case VipType.EXPENSIVE_VIP:
//至尊会员卡打5折
price = getPriceForEXPENSIVE_VIP(goodsPrice);
break;
default:
//假的会员卡涨价
price = getPriceForFalse_VIP(goodsPrice);
break;
}
return price;
}
private double getPriceForNo_VIP(double goodsPrice){
return goodsPrice * 1;
}
private double getPriceForNORMAL_VIP(double goodsPrice){
return goodsPrice * 0.8;
}
private double getPriceForEXPENSIVE_VIP(double goodsPrice){
return goodsPrice * 0.5;
}
private double getPriceForFalse_VIP(double goodsPrice){
return goodsPrice * 1.1;
}
}
2.枚举类型
VipEnum.java
package nopattern;
public enum VipEnum {
NO_VIP,NORMAL_VIP,EXPENSIVE_VIP;
}
Price.java
package nopattern;
public class Price {
public double getPrice(double goodsPrice,VipEnum vipEnum){
double price=0;
switch (vipEnum) {
case NO_VIP:
//没有会员卡不打折
price = getPriceForNo_VIP(goodsPrice);
break;
case NORMAL_VIP:
//普通会员卡打8折
price = getPriceForNORMAL_VIP(goodsPrice);
break;
case EXPENSIVE_VIP:
//至尊会员卡打5折
price = getPriceForEXPENSIVE_VIP(goodsPrice);
break;
default:
//假的会员卡涨价
price = getPriceForFalse_VIP(goodsPrice);
break;
}
return price;
}
private double getPriceForNo_VIP(double goodsPrice){
return goodsPrice * 1;
}
private double getPriceForNORMAL_VIP(double goodsPrice){
return goodsPrice * 0.8;
}
private double getPriceForEXPENSIVE_VIP(double goodsPrice){
return goodsPrice * 0.5;
}
private double getPriceForFalse_VIP(double goodsPrice){
return goodsPrice * 1.1;
}
}
分析:以上修改虽然解决了违背单一原则的问题,但假如书店的会员卡等级增加,会造成代码大量修改,违背了开闭原则,所以,定义一个接口/抽象类,规定所要做的事情,不同的身份实现不同的解决方案,实现多态。
Strategy.java
package withpattern;
/**
* 这个类是用来约束策略的
* 是一个规则
* 抽象类也可以
*/
public interface Strategy {
//计算的方法
double getPrice(double goodsPrice);
}
ExpensiveVipStrategy.java
package withpattern;
public class ExpensiveVipStrategy implements Strategy{
@Override
public double getPrice(double goodsPrice) {
return 0.5*goodsPrice;
}
}
FalseVipStrategy.java
package withpattern;
public class FalseVipStrategy implements Strategy{
public double getPrice(double goodsPrice) {
return 1.1*goodsPrice;
}
}
NormalVipStrategy.java
package withpattern;
public class NormalVipStrategy implements Strategy{
public double getPrice(double goodsPrice) {
return 0.8*goodsPrice;
}
}
NoVipStrategy.java
package withpattern;
public class NoVipStrategy implements Strategy {
public double getPrice(double goodsPrice) {
return 1*goodsPrice;
}
}
1.立即加载方案
package withpattern;
public class Price {
private Strategy strategy;
public Price(Strategy strategy){ //构造函数传参
this.strategy = strategy;
}
public double getGoodsPrice(double goodsPrice){
double result = 0;
result = strategy.getPrice(goodsPrice);//多态
return result;
}
}
2.延迟加载方案
package withpattern;
public class Price {
public Price(){}
public double getGoodsPrice(double goodsPrice,Strategy strategy){
double result = 0;
result = strategy.getPrice(goodsPrice);//多态
return result;
}
}