设计模式-策略模式初体验和总结

设计模式按照功能型分类

创建型模式:

  • 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

结构型模式:

  • 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

行为型模式:

  • 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

策略模式的定义:

  • 定义了算法族,分别封装起来,让它们直接可以互相替换,此模式让算法的变化独立于使用算法的客户.让算法的变化不会影响算法的用户.

  • 适用场景: 对外提供一个统一的接口,有不同的业务实现,上层不需要关心具体的实现细节,比如支付场景,消息消费场景

  • 可以避免多重分支 if else 或者switch分支

  • 属于行为型模式

适用场景举例:

  • 订单支付场景
/**
 * 支付订单
 */
@Data
@Accessors(chain = true)
public class PayOrder {
    /**
     * 订单号
     */
    private String orderId;
    /**
     * 支付用户
     */
    private String userId;
    /**
     * 支付金额
     */
    private Long payAmount;
    /**
     * 支付渠道
     */
    private PayChannelEnums payChannel;
<span class="hljs-keyword">public PayOrder(<span class="hljs-built_in">String orderId, <span class="hljs-built_in">String userId, Long payAmount, PayChannelEnums payChannel) {
    <span class="hljs-keyword">this.orderId = orderId;
    <span class="hljs-keyword">this.userId = userId;
    <span class="hljs-keyword">this.payAmount = payAmount;
    <span class="hljs-keyword">this.payChannel = payChannel;
}

/**

  • 支付类型枚举
    */
    public enum PayChannelEnums {

    /**

    • 支付渠道
      */
      WE_CHAT("wechat", "微信支付"),
      ALI_PAY("alipay", "支付宝支付"),
      JD_PAY("jdpay", "京东白条"),
      UNION_PAY("unionpay", "银联支付");

    private String code;

    private String desc;

    PayChannelEnums(String code, String desc) {
    this.code = code;
    this.desc = desc;
    }

    public String getCode() {
    return code;
    }

    public String getDesc() {
    return desc;
    }

}

/**

  • 支付接口
    */
    public interface Payment {

    /**

    • 标准支付方法
      */
      Boolean doPay(PayOrder payOrder);

    /**

    • 校验余额,钩子方法
      */
      Boolean checkalance(PayOrder payOrder);

}

/**

  • 支付宝支付
    */
    public class AliPay implements Payment {

    static {
    System.out.println("欢迎使用阿里支付");
    }

    @Override
    public Boolean doPay(PayOrder payOrder) {
    return true;
    }

    @Override
    public Boolean checkBalance(PayOrder payOrder) {
    return payOrder.getPayAmount() > 10;
    }
    }

/**

  • 微信支付
    */
    public class WeChatPay implements Payment {

    static {
    System.out.println("欢迎使用微信支付");
    }

    @Override
    public Boolean doPay(PayOrder payOrder) {
    return true;
    }

    @Override
    public Boolean checkBalance(PayOrder payOrder) {
    return payOrder.getPayAmount() > 50;
    }
    }

/**

  • 默认执行的实现类
    */
    public class DefaultPayment implements Payment {

    @Override
    public Boolean doPay(PayOrder payOrder) {
    Payment payment = getPaymentByType(payOrder.getPayChannel());
    if (payment == null) {
    System.out.println("不支持的支付类型");
    return false;
    }
    //校验余额
    Boolean checkalance = payment.checkBalance(payOrder);
    if (!checkalance) {
    System.out.println("您的余额不足,无法支付");
    return false;
    }
    Boolean result = payment.doPay(payOrder);
    if (!result) {
    System.out.println("支付失败");
    } else {
    System.out.println("支付成功");
    }
    return result;
    }

    /**

    • 获取实际的支付类型,也可以通过spring上下文获取,或者通过bean工厂创建
    • @param payChannelEnums
    • @return
      */
      private Payment getPaymentByType(PayChannelEnums payChannelEnums) {
      try {
      if (Objects.equals(payChannelEnums, PayChannelEnums.WE_CHAT)) {
      return new WeChatPay();
      }
      if (Objects.equals(payChannelEnums, PayChannelEnums.ALI_PAY)) {
      return new AliPay();
      }
      if (Objects.equals(payChannelEnums, PayChannelEnums.JD_PAY)) {
      return new JdPay();
      }
      if (Objects.equals(payChannelEnums, PayChannelEnums.UNION_PAY)) {
      return new UnionPay();
      }
      } catch (Exception e) {
      e.printStackTrace();
      }
      return null;
      }

    @Override
    public Boolean checkBalance(PayOrder payOrder) {
    return false;
    }
    }

/**

  • 支付控制台
    */
    public interface PaymentPlatform {

    /**

    • 订单支付入口
    • @param payOrder
    • @return
      */
      Boolean orderPay(PayOrder payOrder);
      }

/**

  • 支付控制台实现类
    */
    public class PaymentPlatformImpl implements PaymentPlatform {

    @Override
    public Boolean orderPay(PayOrder payOrder) {
    //默认执行的实现类实现,不需要关心支付细节
    Payment defaultPayment = new DefaultPayment();
    return defaultPayment.doPay(payOrder);
    }
    }

/**

  • 执行main方法
    */
    public class MainClass {

    public static void main(String[] args) {
    PayOrder payOrder = new PayOrder("O-0001", "lihua", 20L, PayChannelEnums.ALI_PAY);
    PaymentPlatform paymentPlatform = new PaymentPlatformImpl();
    paymentPlatform.orderPay(payOrder);
    }
    }

/**

  • 控制台输出
    */

欢迎使用阿里支付
支付成功

avatar

注意点

  • 支付控制台 PaymentPlatform提供了外部访问的标准入口和参数,内部封装了具体的执行细节

  • payment是支付的标准接口,通过DefaultPayment的getPaymentByType方法来实现创建支付bean和调用支付方法,也可以通过bean工厂和spring上下文来创建bean,策略模式一般会结合工厂模式使用 

  • doPay是为了方便测试,默认返回了支付结果,在实际支付过程中,支付调用一般是先调用预支付接口获取预支付信息,前端唤起支付后,后端服务通过异步获取第三方支付回调的支付结果

支付类工厂代码如下

/**
 * 支付类工厂
 */
@Component
public class PaymentFactory implements ApplicationContextAware {

    private static final Map<String, Payment> paymentMap = new HashMap<>();


    public static Payment getInstance(PayChannelEnums payChannelEnums) {
        return paymentMap.get(payChannelEnums.getCode());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Payment> controllableBeans = applicationContext.getBeansOfType(Payment.class);
        for (Map.Entry<String, Payment> entry : controllableBeans.entrySet()) {
            if (entry.getValue().equals(this)) {
                continue;
            }
            paymentMap.put(entry.getKey(), entry.getValue());
        }
    }
}

/**DefaultPayment调用**/
Payment payment = PaymentFactory.getInstance(payOrder.getPayChannel());

策略模式的优缺点

优点

  • 策略模式复合开闭原则,如果有新的支付算法,只需要实现支付接口,扩展支付的实现就行

  • 避免使用了多条件的if,else,增加了可读性

  • 提高内部算法的保密性和安全性

缺点
  • 客户端调用时必须知道所有的策略,并且自行决定使用哪一个策略
  • 代码中会产生非常多策略类,增加维护难度。
posted @ 2021-04-03 14:32  dis沐雨晨风  阅读(209)  评论(0编辑  收藏  举报