在项目开发过程中,经常会遇到项目代码中充斥着大量的if-else,每次增加类型都要整体代码逻辑看一遍才可以修改,如下代码:
if("wx".equals(type)){
do...
}else if("zfb".equals(type)){
do...
}else if("bank".equals(type)){
do...
}else{
do...
}
当业务逻辑不变时使用以上代码是没有什么问题的,但业务经常变动时,就需要经常改动代码,如果后期再增加分支,每次改动都需要对每个分支都做测试,增加测试工作量同时要不利于代码维护,也违反开闭原则和单一职责,这时候我们就要想办法来优化这样的代码.
代码改造:
下面我们使用策略模式+工厂来改造以上代码,
1. 使用idea创建一个SpirngBoot工程,创建支付类枚举,创建一个PayHandler接口类
public enum PayChannelEnum {
ZFB("支付宝支付"),
WX("微信支付"),
BANK("银行卡支付");
private String desc;
private String beanName;
PayChannelEnum(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
public interface PayHandler {
PayChannelEnum getPayChannel();
void pay();
}
2. 创建三个支付通道的处理类,实现PayHandler,注意加@Component
@Component
public class BankPayHandler implements PayHandler {
@Override
public PayChannelEnum getPayChannel() {
return PayChannelEnum.BANK;
}
@Override
public void pay() {
System.out.println("银行卡支付");
}
}
@Component
public class WxPayHandler implements PayHandler {
@Override
public PayChannelEnum getPayChannel() {
return PayChannelEnum.WX;
}
@Override
public void pay() {
System.out.println("微信支付");
}
}
@Component
public class ZfbPayHandler implements PayHandler {
@Override
public PayChannelEnum getPayChannel() {
return PayChannelEnum.ZFB;
}
@Override
public void pay() {
System.out.println("支付宝支付");
}
}
3. 创建工厂类,实现InitializingBean, ApplicationContextAware.
@Component
public class PayFactory implements InitializingBean, ApplicationContextAware {
private static final Map<String,PayHandler> payHandlerMap = new ConcurrentHashMap<>();
private ApplicationContext applicationContext;
public PayHandler getPayHandler(String name){
return payHandlerMap.get(name);
}
@Override
public void afterPropertiesSet() throws Exception {
applicationContext.getBeansOfType(PayHandler.class)
.values()
.forEach(handler -> payHandlerMap.put(handler.getPayChannel().name(),handler));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
4. 使用
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
PayFactory payFactory = (PayFactory) context.getBean("payFactory");
payFactory.getPayHandler(PayChannelEnum.ZFB.name()).pay();
}
}
总结:
根据上面代码我们能看出策略模式优点缺点很明显,在项目中使用要根据自己业务的实际情况来确定.
优点: 符合单一职责和开闭原则,使代码易于扩展和复用
缺点: 每个类型都需要一个实现一个策略类,会使代码出现"膨胀",调用方要预先知道所有的类型