策略模式
以支付为例,用户在支付商品时,可以有多种支付方式,如支付宝,微信,现金。当支付方式增多,支付策略复杂化,我们就要考虑使用策略模式,这样可以避免if else 成堆出现,既不美观也很容易出错。
假设目前支持支付宝,微信,现金支付。有如下不同支付优惠
支付方式 | 支付优惠策略 |
---|---|
支付宝 | 满100,每10元减1元。不满100 ,98折扣 |
微信 | 全部98折扣 |
现金 | 无优惠 |
… | … |
-
定义支付接口
public interface Pay { void pay(Integer amount); }
-
实现支付接口(不同的支付方式有不同的策略)
支付宝支付
@Component public class AlPay implements Pay { @Override public void pay(Integer amount) { //实现满10减1 if (amount >= 100) { int count = amount / 10; System.out.println("支付宝支付" + (amount - count)); }else { System.out.println("支付宝支付" + amount*0.98); } } }
微信支付
@Component public class WxPay implements Pay { @Override public void pay(Integer amount) { System.out.println("微信支付" + amount * 0.98); } }
现金支付
@Component public class CashPay implements Pay { @Override public void pay(Integer amount) { System.out.println("现金支付" + amount); } }
-
定义支付枚举
这里有个要求是payName必须和Bean的名字一致。
通过枚举的ordinal 我们知道AlPay是0,WxPay是1,CashPay是2,我们就建立了一对一关系,只要给我数字这里就可以通过getPayTypeEnum()返回对应的枚举
@Getter @AllArgsConstructor public enum PayTypeEnum { AlPay("alPay"), WxPay("wxPay"), CashPay("cashPay"); private final String payName; public static PayTypeEnum getPayTypeEnum(String ordinal) { return Arrays.stream(PayTypeEnum.values()) .filter(payTypeEnum -> String.valueOf(payTypeEnum.ordinal()).equals(ordinal)) .findFirst().orElseThrow(() -> new IllegalArgumentException("支付类型不存在")); } }
-
Controller
接收支付类型和支付金额
@RestController public class TestStrategyController { @Autowired private PayStrategyContext payStrategyContext; @RequestMapping("/pay") public void get(@RequestParam("type") String type, @RequestParam("amount") String amount) { //通过数字获取对应的支付枚举对象 PayTypeEnum payTypeEnum = PayTypeEnum.getPayTypeEnum(type); Pay pay = payStrategyContext.getPayType(payTypeEnum); pay.pay(Integer.valueOf(amount)); } }
-
支付策略上下文
通过spring依赖注入Map型,Key为Bean的名字,Value为现实类。通过Map的get方法提供Bean的名字,获取对应的支付现实类。
@Component public class PayStrategyContext { @Resource private Map<String, Pay> maps; public Pay getPayType(PayTypeEnum payTypeEnum) { return maps.get(payTypeEnum.getPayName()); } }