asp中注释掉代码_深度解析:如何替换掉代码中的ifelse,我女朋友看完都会了

平时我们在写代码时,需要针对不同情况处理不同的业务逻辑,用得最多的就是if和else。 但是如果情况太多,就会出现一大堆的“if else”,这就是为什么很多遗留系统中,一个函数可能出现上千行的代码。当然你说可以通过抽取方法或者类来实现,每一个情况交给一个方法或者对应一个类来处理,但是这样做只是看起来代码整洁了一些,还是有大量的”if else",后面有新的逻辑时,又要添加更多的“if else",没有从根本上解决问题。

举个例子,短信发送业务的实现,一般公司会接入多个短信供应商,比如梦网、玄武、阿里云等多个短信平台(我们称之为短信渠道),可能需要针对不同的短信类型或者短信平台的稳定性来切换短信渠道:1.比如阿里云短信管控很严,带营销字样的短信不让发送,则营销类短信需要使用其他短信渠道来发送;

2.也有可能某个短信平台服务挂了暂时不可用,需要切换到另一个短信渠道;

3.某些短信平台有优惠,则需要临时切换到该短信渠道发送短信;

4.…

71235c0d31d62127feca288c889d8652.png
代码实现

上面的业务场景简单来说就是:针对不同的短信渠道来调用对应的短信平台接口实现短信发送。短信渠道一般配置在文件中,或者配置在数据库中。

代码实现如下(注意下面所有的代码都不能直接运行,只是关键逻辑部分的示例代码):

烂代码示例

我们有一个短信发送类:SmsSendService,里面有一个send方法发送短信SmsSendService.java

public class SmsSendService{    /**     * @Param phoneNo 手机号     * @Param content 短信内容     */    public void send(String phoneNo,String content){        //从配置中读取 短信渠道        String channelType=config.getChannelType();        //如果是短信渠道A,则调用渠道A的api发送        if(Objects.equals(channelType,"CHANNEL_A")){            System.out.println("通过短信渠道A发送短信");        }        //如果是短信渠道B,则调用渠道B的api发送        else if(Objects.equals(channelType,"CHANNEL_B")){            System.out.println("通过短信渠道B发送短信");        }    }}

如果某天增加了一个短信渠道C,那么接着追加一个”else if…"

//... 此处省略部分代码 ...//从配置中读取 短信渠道String channelType=config.getChannelType();//如果是短信渠道A,则调用渠道A的api发送if(Objects.equals(channelType,"CHANNEL_A")){    System.out.println("通过短信渠道A发送短信");}//如果是短信渠道B,则调用渠道B的api发送else if(Objects.equals(channelType,"CHANNEL_B")){    System.out.println("通过短信渠道B发送短信");}//ADD: 如果是短信渠道C,则调用渠道C的api发送else if(Objects.equals(channelType,"CHANNEL_C")){    System.out.println("通过短信渠道C发送短信");}//... 此处省略部分代码 ...

如果又加其他短信渠道了呢?你又写一个“else if …" ?显然这种做法不可取,也不符合SOLID原则中的”开闭原则“ ——对扩展开放,对更改封闭。这样我们每次都需要修改原有代码(对更改没有封闭),不断的添加”if else"。

接下来我们把代码优化一下:

优化代码1

定义一个短信渠道的接口 SmsChannelService,所有的短信渠道API都实现该接口;短信渠道接口 SmsChannelService.java

public interface SmsChannelService{    //发送短信    void send(String phoneNo,String content);}

短信渠道A SmsChannelServiceImplA.java

public class SmsChannelServiceImplA implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道A发送短信");    }}

短信渠道B SmsChannelServiceImplB.java

public class SmsChannelServiceImplB implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道B发送短信");    }}

通过工厂类来初始化所有短信渠道serviceSmsChannelFactory.java

public class SmsChannelFactory {    private Map serviceMap;    //初始化工厂,将所有的短信渠道Service放入Map中    public SmsChannelFactory(){        //渠道类型为 key , 对应的服务类为value :        serviceMap=new HashMap(2);        serviceMap.put("CHANNEL_A",new SmsChannelServiceImplA());        serviceMap.put("CHANNEL_B",new SmsChannelServiceImplB());    }    //根据短信渠道类型获得对应渠道的Service    public SmsChannelService buildService(String channelType){        return serviceMap.get(channelType);    }}

在原来的SmsSendService中调用不同短信渠道的接口。原来的 SmsSendService 类优化如下

public class SmsSendService {    private SmsChannelFactory smsChannelFactory;    public SmsSendService(){        smsChannelFactory=new SmsChannelFactory();    }    public void send(String phoneNo,String content){        //从配置中读取 短信渠道        String channelType=config.getChannelType();        //获取渠道类型对应的服务类        SmsChannelService channelService=smsChannelFactory.buildService(channelType);        //发送短信        channelService.send(phoneNo,content);    }}

这样SmsSendService类非常简洁,把“if else"干掉了,如果我要增加一个短信渠道C,无需再次更改 SmsSendService 类。只需要增加一个类 SmsChannelServiceImplC 实现 SmsChannelService 接口,然后在工厂类 SmsChannelFactory 中增加一行初始化 SmsChannelServiceImplC 的代码即可。

增加短信渠道C的实现 SmsChannelServiceImplC.java

public class SmsChannelServiceImplC implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道C发送短信");    }}

修改工厂类 SmsChannelFactory.java

public class SmsChannelFactory {    private Map serviceMap;    //初始化 serviceMap ,将所有的短信渠道Service放入Map中    public SmsChannelFactory(){        //渠道类型为 key , 对应的服务类为value :        serviceMap=new HashMap(3);        serviceMap.put("CHANNEL_A",new SmsChannelServiceImplA());        serviceMap.put("CHANNEL_B",new SmsChannelServiceImplB());        //ADD 增加一行 SmsChannelServiceImplC 的初始化代码         serviceMap.put("CHANNEL_C",new SmsChannelServiceImplC());    }    //根据渠道类型构建短信渠道Service    public SmsChannelService buildService(String channelType){        return serviceMap.get(channelType);    }}

“if else"是干掉了,但还是得修改原来的类 SmsChannelFactory ,不满足"开闭原则",有没有更好的方式呢?

我们通过使用spring的依赖注入进一步优化代码:

优化代码2

SmsChannelService 接口增加 getChannelType() 方法,这一步很关键。

public interface SmsChannelService {    //发送短信    void send(String phoneNo,String content);    //关键:增加getChannelType()方法,子类实现这个方法用于标识出渠道类型    String getChannelType();}

子类增加该方法的实现,并加上 @Service 注解,使其让spring容器管理起来SmsChannelServiceImplA.java

@Servicepublic class SmsChannelServiceImplA implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道A发送短信");    }    //关键:增加 getChannelType() 实现    public String getChannelType() {        return "CHANNEL_A";    }}

SmsChannelServiceImplB.java

@Servicepublic class SmsChannelServiceImplB implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道B发送短信");    }    //关键:增加 getChannelType() 实现    public String getChannelType() {        return "CHANNEL_B";    }}

修改 SmsChannelFactory 类: 这一步也很关键。SmsChannelFactory.java

@Servicepublic class SmsChannelFactory {    private Map serviceMap;    /*注入:通过spring容器将所有实现 SmsChannelService 接口的类的实例注入到 serviceList 中*/    @Autowired    private List serviceList;    /*通过 @PostConstruct 注解,在 SmsChannelFactory 实例化后,来初始化 serviceMap */    @PostConstruct    private void init(){        if(CollectionUtils.isEmpty(serviceList)){            return ;        }        serviceMap=new HashMap(serviceList.size());        //将 serviceList 转换为 serviceMap        for (SmsChannelService channelService : serviceList) {            String channelType=channelService.getChannelType();            //重复性校验,避免不同实现类的 getChannelType() 方法返回同一个值。            if(serviceMap.get(channelType)!=null){                throw new RuntimeException("同一个短信渠道只能有一个实现类");            }            /*渠道类型为 key , 对应的服务类为value :            与“优化代码1”中的通过手工设置“CHANNEL_A"、"CHANNEL_B"相比,            这种方式更加自动化,后续在增加“CHANNEL_C"无需再改此处代码*/            serviceMap.put(channelType,channelService);        }    }    //根据渠道类型获取对应短信渠道的Service    public SmsChannelService buildService(String channelType){        return serviceMap.get(channelType);    }}

SmsSendService 加上 @Service 注解。通过 @Autowired 注入 SmsChannelFactorySmsSendService.java

@Servicepublic class SmsSendService {    @Autowired    private SmsChannelFactory smsChannelFactory;    public void send(String phoneNo,String content){        //从配置中读取短信渠道类型        String channelType=config.getChannelType();        //构建渠道类型对应的服务类        SmsChannelService channelService=smsChannelFactory.buildService(channelType);        //发送短信        channelService.send(phoneNo,content);    }}

这时,如果需要添加一个渠道C,那真的只需要添加一个 SmsChannelServiceImplC 即可,再也不用改原有代码,完全遵循“开闭原则”。

SmsChannelServiceImplC.java

@Servicepublic class SmsChannelServiceImplC implements SmsChannelService {    public void send(String phoneNo, String content) {        System.out.println("通过短信渠道C发送短信");    }    public String getChannelType() {        return "CHANNEL_C";    }}

总结通过上述优化很好的去掉了 “if else" ,再也不会出现”又臭又长“像”卫生卷纸"一样的代码了,而且完全遵循”开闭原则"。spring是个好东西,关键看你怎么用。

看完有什么不懂的欢迎在下方留言评论,记得点个赞哦!

原文链接:https://blog.51cto.com/14801695/2495597

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值