前言
也許我們的代碼中遇到過多重判斷if-else語句,但是這樣的代碼可讀性差,並且當擴展時,違反了“開閉原則”。阿里開發規范中提到的解決方法有:衛語句,策略模式,狀態模式。本文講述的是通過策略模式來解決多重判斷if-else語句問題。
github代碼地址:https://github.com/Chenrencun/pay-strategy
正文
一、多重判斷if-else代碼
我們通過支付接口的例子來講述。代碼如下:
1、Controller層
@RestController public class PayController { @Autowired private PayService payService; @RequestMapping("/pay") public String pay(String type, String amount){ return payService.pay(type, amount); } }
2、Service層
public interface PayService { /** * 支付接口 * @param type 支付類型 * @param amount 支付金額 * @return */ String pay(String type, String amount); } @Service public class PayServiceImpl implements PayService{ private static String MSG = "使用 %s ,消費了 %s 元"; @Override public String pay(String type, String amount) { if (PayEnum.ALI_PAY.getType().equals(type)){ // 支付寶支付 return String.format(MSG, PayEnum.ALI_PAY.getDescription(), amount); } else if (PayEnum.WECHAT_PAY.getType().equals(type)) { // 微信支付 return String.format(MSG, PayEnum.WECHAT_PAY.getDescription(), amount); } else if (PayEnum.UNION_PAY.getType().equals(type)) { // 銀聯支付 return String.format(MSG, PayEnum.UNION_PAY.getDescription(), amount); } return "輸入的支付類型錯誤!"; } }
3、Enum枚舉類
public enum PayEnum { ALI_PAY("ali", "支付寶支付"), WECHAT_PAY("wechat", "微信支付"), UNION_PAY("union", "銀聯支付"); private String type; private String description; PayEnum(String type, String description) { this.type = type; this.description = description; } public String getType() { return type; } public String getDescription() { return description; } }
當需要增加一個信用卡支付時,需要修改原來的代碼,這樣就違法了“開閉原則”。
二、策略模式代碼
主要是Service層代碼有所改變。
1、Service層
public interface PayService { /** * 支付接口 * @param type 支付類型 * @param amount 支付金額 * @return */ String pay(String type, String amount); } @Service public class PayServiceImpl implements PayService{ private static String MSG = "使用 %s ,消費了 %s 元"; @Override public String pay(String type, String amount) { PayStrategy payStrategy = PayStrategyFactory.getPayStrategy(type); if (payStrategy == null){ return "輸入的支付類型錯誤!"; } return payStrategy.pay(type, amount); } }
2、對多重判斷if-else語句的改造
public interface PayStrategy { String MSG = "使用 %s ,消費了 %s 元"; String pay(String type, String amount); } @Component("aliPayStrategy") public class AliPayStrategyImpl implements PayStrategy{ @Override public String pay(String type, String amount) { return String.format(MSG, PayEnum.ALI_PAY.getDescription(), amount); } } @Component("wechatPayStrategy") public class WechatPayStrategyImpl implements PayStrategy{ @Override public String pay(String type, String amount) { return String.format(MSG, PayEnum.WECHAT_PAY.getDescription(), amount); } } @Component("unionPayStrategy") public class UnionPayStrategyImpl implements PayStrategy{ @Override public String pay(String type, String amount) { return String.format(MSG, PayEnum.UNION_PAY.getDescription(), amount); } }
3、修改后的枚舉類
public enum PayEnum { ALI_PAY("ali", "支付寶支付", "aliPayStrategy"), WECHAT_PAY("wechat", "微信支付", "wechatPayStrategy"), UNION_PAY("union", "銀聯支付", "unionPayStrategy"); private String type; private String description; private String beanName; PayEnum(String type, String description, String beanName) { this.type = type; this.description = description; this.beanName = beanName; } public String getType() { return type; } public String getDescription() { return description; } public String getBeanName() { return beanName; } public static PayEnum getByType(String type){ if (type == null){ return null; } for (PayEnum payEnum:values() ) { if (payEnum.getType().equals(type)){ return payEnum; } } return null; } }
4、通過以下工具類,能夠獲取到PayStrategy實現類關聯。
public class SpringContextUtil implements ApplicationContextAware { /** * 上下文對象實例 */ private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext(){ return applicationContext; } public static <T> T getBean(String name){ return (T)getApplicationContext().getBean(name); } public static <T> T getBean(String name, Class<T> clazz){ return getApplicationContext().getBean(name, clazz); } }
5、Service調用PayStrategy的工廠類,返回PayStrategy的實現類
public class PayStrategyFactory { /** * 根據type獲取對應PayStrategy實現類 * @param type * @return */ public static PayStrategy getPayStrategy(String type){ PayEnum payEnum = PayEnum.getByType(type); if (payEnum == null){ return null; } return SpringContextUtil.getBean(payEnum.getBeanName(), PayStrategy.class); } }
通過這樣的改造,當我們增加一個信用卡支付時,只需要添加一個PayStrategy的實現類,並在PayEnum枚舉類添加一個信用卡支付的成員就可以了。