一、策略模式简介
策略模式定义:是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户
策略模式优点:可以避免多重分支的if…else…和switch语句
策略模式的使用场景:
- 假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
- 一个系统需要动态的在几种算法中选择一种。
策略模式案例:
JDK中Comparator接口中的int compare(T o1, T o2);方法,在Arrays、TreeMap里可以自定义排序规则
Arrays.class
TreeMap.class
- Spring中的Resource接口
- Spring中InstantiationStrategy接口,主要对类进行初始化策略,有两个策略实现类,它们不是平级而是继承关系(策略模式中不同策略也可以继承)
CglibSubclassingInstantiationStrategy:Cglib的初始方式
SimpleInstantiationStrategy:JDK的初始化方式
类图
二、简单代码案例
案例:购买东西有活动时,会有抵用券、返现、拼团等减免金额的策略
优惠策略抽象接口
public interface PromotionStrategy {
/**
* 执行优惠
*/
void doPromotion();
}
没有优惠
public class EmptyStrategy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("无促销活动");
}
}
抵用券
public class CouponStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("领取优惠券,课程的价格直接减去优惠券面值抵扣");
}
}
返现
public class CashbackStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现促销,返回的金额转到支付宝账号");
}
}
拼团
public class GroupBuyStrategy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("拼团,满20人成团,全团享受团购价格");
}
}
优惠活动
public class PromotionActivity {
PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy){
this.promotionStrategy = promotionStrategy;
}
/**
* 执行优惠活动
*/
public void execute(){
this.promotionStrategy.doPromotion();
}
}
测试一
public static void main(String[] args) {
// 618优惠券活动
PromotionActivity activity618 = new PromotionActivity(new CouponStrategy());
activity618.execute();
// 双11返现活动
PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());
activity1111.execute();
}
测试二
public static void main(String[] args) {
PromotionActivity promotionActivity = null;
String promotionKey = "COUPON";
if (StringUtils.equals(promotionKey,"COUPON")){
promotionActivity = new PromotionActivity(new CouponStrategy());
}else if (StringUtils.equals(promotionKey,"CASHBACK")){
promotionActivity = new PromotionActivity(new CashbackStrategy());
} // .......
promotionActivity.execute();
}
简单实现完发现还可以通过单例模式+简单工厂模式简化代码,用唯一标志选择策略
工厂类
public class PromotionStrategyFactory {
private static final Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new ConcurrentHashMap<String,PromotionStrategy>();
private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy();
static {
PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupBuyStrategy());
}
private PromotionStrategyFactory(){
}
public static PromotionStrategy getPromotionStrategy(String promotionKey){
PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
}
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
}
测试
public static void main(String[] args) {
String promotionKey = "GROUPBUY";
PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
promotionActivity.execute();
}
附上类结构图
三、简单代码二案例
案例:用户下单支付,可以选择多种支付渠道
支付抽象类
public abstract class Payment {
/**
* 支付信息
* @return
*/
public abstract String getName();
/**
* 余额
* @param uid
* @return
*/
protected abstract double queryBalance(String uid);
/**
* 支付
* @param uid
* @param amount
* @return
*/
public MsgResult pay(String uid,double amount){
if (queryBalance(uid) < amount){
return new MsgResult(500,"支付失败","余额不足");
}else {
return new MsgResult(200,"支付成功","支付金额: " + amount);
}
}
}
支付宝支付
public class AliPay extends Payment{
@Override
public String getName() {
return "支付宝";
}
@Override
protected double queryBalance(String uid) {
return 900;
}
}
京东白条
public class JDPay extends Payment{
@Override
public String getName() {
return "京东白条";
}
@Override
protected double queryBalance(String uid) {
return 500;
}
}
银联支付
public class UnionPay extends Payment {
@Override
public String getName() {
return "银联支付";
}
@Override
protected double queryBalance(String uid) {
return 120;
}
}
微信支付
public class WechatPay extends Payment {
@Override
public String getName() {
return "微信支付";
}
@Override
protected double queryBalance(String uid) {
return 256;
}
}
返回消息类
public class MsgResult {
private int code;
private Object data;
private String msg;
public MsgResult(int code, Object data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
@Override
public String toString() {
return "MsgResult{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\'' +
'}';
}
}
订单类
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid, String orderId, double amount) {
this.uid = uid;
this.orderId = orderId;
this.amount = amount;
}
public MsgResult pay(String payKey){
Payment payment = PayStrategy.get(payKey);
System.out.println("欢迎使用" + payment.getName());
System.out.println("本次交易金额为:" + amount + ",开始扣款...");
return payment.pay(uid,amount);
}
@Override
public String toString() {
return "Order{" +
"uid='" + uid + '\'' +
", orderId='" + orderId + '\'' +
", amount=" + amount +
'}';
}
}
支付策略工厂
public class PayStrategy {
public static final String ALI_PAY = "AliPay";
public static final String JD_PAY = "JDPay";
public static final String WECHAT_PAY = "WchatPay";
public static final String UNION_PAY = "UnionPay";
public static final String DEFAULT_PAY = "AliPay";
private static Map<String,Payment> payStrategy = new HashMap<String,Payment>();
static {
payStrategy.put(ALI_PAY,new AliPay());
payStrategy.put(JD_PAY,new JDPay());
payStrategy.put(WECHAT_PAY,new WechatPay());
payStrategy.put(UNION_PAY,new UnionPay());
payStrategy.put(DEFAULT_PAY,new AliPay());
}
public static Payment get(String payKey){
if (!payStrategy.containsKey(payKey)){
return payStrategy.get(DEFAULT_PAY);
}
return payStrategy.get(payKey);
}
}
测试
public class PayStrategyTest {
public static void main(String[] args) {
Order order = new Order("1", "2021110", 1342.45);
MsgResult result = order.pay(PayStrategy.ALI_PAY);
System.out.println(result);
}
}
附上类结构图:
四、总结
策略模式的优点:
- 策略模式符合开闭原则。
- 避免使用多重条件转移语句,如if…else…语句、switch语句。
- 使用策略模式可以提高算法的保密性和安全性。
策略模式的缺点:
- 客户端必须知道所有的策略,并且用户自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。
还等什么小编推荐自己的linuxC/C++语言交流群:【1106675687】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!前100名进群领取,额外赠送一份价值199的C/C++、linux资料包含(视频教程、电子书、实战项目及代码),下面部分展示。