美文网首页安卓Android知识手机移动程序开发
消除if else,让代码更加好读易懂

消除if else,让代码更加好读易懂

作者: foreveruseful | 来源:发表于2017-03-05 02:25 被阅读1463次

    本文使用JAVA编程语言,其他语言道理一样通的,支持lambda表达式或者函式编程的语言写起来更加简单优雅。
    相信大家做了一段时间开发之后,都免不了看到一种尴尬的场面,就是条件分支太多了,一堆if、else,甚至还有层层的嵌套,就算不用if else,可是用switch case还是换汤不换药啊,业务这么复杂,不用条件分支,臣妾做不到啊。看下面的例子:
    假设这么一个场景,你的程序是一个消息处理的程序,这里场景其实是简化的抽取了微信公众账号开发消息处理的一部分来说明问题,消息类型有三种,图片、文字、事件,事件又分为三种子事件,分别为菜单事件、扫码事件、关注事件,每一种消息处理方式不同*,最原始大家的代码如下(下面代码仅为说明问题虚构,并非实际项目中的代码,并忽略了异常处理):

    enum MsgType{
        IMAGE, TEXT, EVENT
    }
    enum EventType{
        MENU, SCAN, SUBSCRIBE
    }
    class Msg {
        MsgType type;
        EventType subType;
        // 其他内容
    }
    void handle(Msg msg) {
        if(MsgType.IMAGE.equals(msg.type)) {
            handleImageMsg(msg);
        } else if(MsgType.TEXT.equals(msg.type)) {
            handleTextMsg(msg);
        } else if(MsgType.EVENT.equals(msg.type)) {
            if(EventType.MENU.equals(msg.subType)) {
                handleMenuMsg(msg);
            } else if(EventType.SCAN.equals(msg.subType)) {
                handleScanMsg(msg);
            } else if(EventType.SUBSCRIBE.equals(msg.subType)) {
                handleSubscribeMsg(msg);
            }
        }
    }
    

    这样的代码有问题吗?咋一看,没啥问题啊,大家不都是这样处理业务问题的吗?难道面对这样的业务需求,还有其他的方式处理吗?不做条件判断臣妾真的做不到啊!!!
    别伤心,方法是有的,我第一次碰到这种问题的时候,也是头都大啊,我接手的是前人的代码,里面的if else漫天都是,比上面的场景复杂多了,以我当时的技术水平,愣是没法完全看懂业务逻辑,嵌套层级太TM多了,抓狂啊,我上辈子得罪谁了?!!要我来处理这样的摊子,香菇,蓝瘦,然而,任务既然落到我的手里了,我不能不处理啊,总不能辞职一走了之吧?琢磨里几天,真的寝食难宁啊。
    突然想起当时非常流行的一种界面风格,扁平化,这种错综复杂的代码,是不是也可以像微软的手机界面一样,扁平化平铺出来呢?于是撸起袖子撸代码(下面代码还是仅为说明问题而虚构的,并非实际项目中的代码,并忽略了异常处理):

    public interface Flatten {
        <T, F> T work(F f);
    }
    // 消息实体也添加了点修改,增加getKey()方法为了产生一个Handler与消息对应的key
    class Msg {
        MsgType type;
        EventType subType;
        String getKey() {
            if(subType != null){
               return type.name();
            } else {
              return type.name() + "_" + subType.name();
            }
        }
        // 其他内容
    }
    public class ImageMsgHandler implements Flatten{
        @Override
        public <T, F> T work(F f) {
            System.out.println("Incoming message: " + f);
            return (T) "Image processed";
        }
    }
    public class TextMsgHandler implements Flatten {
        @Override
        public <T, F> T work(F f) {
            System.out.println("Incoming message: " + f);
            return (T) "Text processed";
        }
    }
    // 其它对应的处理器略
    
    // 使用方式如下
    static HashMap<String, Flatten> workers = new HashMap<>();
    // 或者
    static HashMap<String, Class<? extends Flatten>> workers2 = new HashMap<>();
    static void init() {
        workers.put(TEXT.name(), new TextMsgHandler());
        workers.put(IMAGE.name(), new ImageMsgHandler());
        // 其它处理器的注册略
    
        // 或者可以下面这样,看具体情况,一般情况建议第一种单例模式,节省反射的消耗和内存的消耗
        workers2.put(TEXT.name(), TextMsgHandler.class);
        workers2.put(IMAGE.name(), ImageMsgHandler.class);
        // 其它处理器的注册略
    }
    static Object handle(Msg msg) {
        return workers.get(msg.getKey()).work(msg);
        // 或者
        return workers2.get(msg.getKey()).newInstance().work(msg);
    }
    

    然后我又花了一小段时间,把当时的项目里面的每一个条件里的内容拷贝出来,一个条件变成一个类,终于可以看懂了!!!虽然那时候的代码多了,都是框架性代码,现在用上java 8了,lambda表达式直接省掉每个条件写一个类,非常的舒服。
    安卓下面有一个场景特别适合使用这种玩法,暴露接口给webview的时候,可以统一一个入口,然后通过第一个参数作为条件选择,选择相应的处理。好,文章就到这里,祝大家每天准时下班。

    相关文章

      网友评论

      • 北斗星晨:换成类更复杂,用查表法
        4f02f1f15e16: @FlashGeek 他这个就是泛化的查表法啊,常规的查表法在这里就相当整数类型的key而已,并且用数组代替map,常规查表法的问题是要做越界检查,还要确保下标计算不会重复,所以限制很大啊。另外,熟悉设计模式的一眼就应该能看出是策略模式的使用了吧。
      • Rokuki:目前大二,看楼主写的代码反而看不懂。。果然还是功夫不到家😂
        Rokuki: @foreveruseful 🙏受教了
        foreveruseful:可能写的不够清楚,:joy:
        指导思想就是把if里面的条件组合出来,经过简单的处理,比如转换成字符串,产生一个可以用作HashMap或字典这些映射类型的数据结构里作为key的值,然后实际执行代码就放在了HashMap或字典的key映射的处理函数(类)里了。

      本文标题:消除if else,让代码更加好读易懂

      本文链接:https://www.haomeiwen.com/subject/zxksgttx.html