设计模式(三)之策略模式(Strategy Pattern)深入浅出

策略模式定义:

  • 是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
  • 属于行为型模式。

策略模式优点:可以避免多重分支的if...else...和switch语句

策略模式的使用场景:

  • 假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
  • 一个系统需要动态的在几种算法中选择一种。

 策略模式案例:

  • JDK中Comparator接口中的int compare(T o1, T o2);方法,在Arrays、TreeMap里可以自定义排序规则

Arrays.class

 

TreeMap.class

  • Spring中的Resource接口
  • Spring中InstantiationStrategy接口,主要对类进行初始化策略,有两个策略实现类,它们不是平级而是继承关系(策略模式中不同策略也可以继承)
  1. CglibSubclassingInstantiationStrategy:Cglib的初始方式
  2. SimpleInstantiationStrategy:JDK的初始化方式

类图

 生活场景案例

案例:购买东西有活动时,会有抵用券、返现、拼团等减免金额的策略

优惠策略抽象接口

/**
 * @ClassName PromotionStrategy
 * @Author 周聪
 * @Date 2021/1/10 17:58
 * @Version 1.0
 * @Description 优惠策略的抽象
 */
public interface PromotionStrategy {

    /**
     * 执行优惠
     */
    void doPromotion();
}

没有优惠

/**
 * @ClassName EmptyStrategy
 * @Author 周聪
 * @Date 2021/1/10 17:59
 * @Version 1.0
 * @Description 无优惠
 */
public class EmptyStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("无促销活动");
    }
}

抵用券

/**
 * @ClassName CouponStrategy
 * @Author 周聪
 * @Date 2021/1/10 18:01
 * @Version 1.0
 * @Description 优惠券抵扣
 */
public class CouponStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("领取优惠券,课程的价格直接减去优惠券面值抵扣");
    }
}

返现

/**
 * @ClassName CashbackStrategy
 * @Author 周聪
 * @Date 2021/1/10 18:04
 * @Version 1.0
 * @Description 返现
 */
public class CashbackStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("返现促销,返回的金额转到支付宝账号");
    }
}

拼团

/**
 * @ClassName GroupBuyStrategy
 * @Author 周聪
 * @Date 2021/1/10 18:05
 * @Version 1.0
 * @Description 团购
 */
public class GroupBuyStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("拼团,满20人成团,全团享受团购价格");
    }
}

优惠活动

/**
 * @ClassName PromotionActivity
 * @Author 周聪
 * @Date 2021/1/10 18:07
 * @Version 1.0
 * @Description 优惠活动
 */
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();
    }

简单实现完发现还可以通过单例模式+简单工厂模式简化代码,用唯一标志选择策略

工厂类

/**
 * @ClassName PromotionStrategyFactory
 * @Author 周聪
 * @Date 2021/1/10 18:28
 * @Version 1.0
 * @Description 简单工厂+ 注册式饿汉式单例
 */
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();
    }

附上类结构图

 

 

业务场景案例

案例:用户下单支付,可以选择多种支付渠道

支付抽象类

/**
 * @ClassName Payment
 * @Author 周聪
 * @Date 2021/1/10 18:55
 * @Version 1.0
 * @Description 支付抽象
 */
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);
        }
    }
}

支付宝支付

/**
 * @ClassName AliPay
 * @Author 周聪
 * @Date 2021/1/10 18:54
 * @Version 1.0
 * @Description 支付宝支付
 */
public class AliPay extends Payment{
    @Override
    public String getName() {
        return "支付宝";
    }

    @Override
    protected double queryBalance(String uid) {
        return 900;
    }
}

京东白条

/**
 * @ClassName JDPay
 * @Author 周聪
 * @Date 2021/1/10 19:45
 * @Version 1.0
 * @Description
 */
public class JDPay extends Payment{
    @Override
    public String getName() {
        return "京东白条";
    }

    @Override
    protected double queryBalance(String uid) {
        return 500;
    }
}

银联支付

/**
 * @ClassName UnionPay
 * @Author 周聪
 * @Date 2021/1/10 19:47
 * @Version 1.0
 * @Description 银联支付
 */
public class UnionPay extends Payment {
    @Override
    public String getName() {
        return "银联支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 120;
    }
}

微信支付

/**
 * @ClassName WechatPay
 * @Author 周聪
 * @Date 2021/1/10 19:46
 * @Version 1.0
 * @Description
 */
public class WechatPay extends Payment {
    @Override
    public String getName() {
        return "微信支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 256;
    }
}

返回消息类

/**
 * @ClassName MsgResult
 * @Author 周聪
 * @Date 2021/1/10 18:49
 * @Version 1.0
 * @Description 返回消息类
 */
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 + '\'' +
                '}';
    }
}

订单类

/**
 * @ClassName Order
 * @Author 周聪
 * @Date 2021/1/10 18:48
 * @Version 1.0
 * @Description
 */
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 +
                '}';
    }
}

支付策略工厂

/**
 * @ClassName PayStrategy
 * @Author 周聪
 * @Date 2021/1/10 19:51
 * @Version 1.0
 * @Description 支付策略工厂
 */
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);

    }
}

测试

/**
 * @ClassName PayStrategyTest
 * @Author 周聪
 * @Date 2021/1/10 19:48
 * @Version 1.0
 * @Description
 */
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语句。
  • 使用策略模式可以提高算法的保密性和安全性。

策略模式的缺点:

  • 客户端必须知道所有的策略,并且用户自行决定使用哪一个策略类。
  • 代码中会产生非常多策略类,增加维护难度。

以上对策略模式的介绍到此结束,欢迎批评指正。 附:源码地址

posted @ 2021-01-10 21:22  IT学无止境99  阅读(167)  评论(0编辑  收藏  举报