开发笔记(一):避免重复代码

最近大家都在忙着功能优化和BUG,而我却比较闲,开发的模块没有什么BUG,也没什么需要优化的,便抽些时间来改下正在开发项目中的一些坏代码。

    //坏代码
    SC_ResponseMsgProto.Builder responseMsgBuilder = SC_ResponseMsgProto.newBuilder();//重复一
    DataMsgProto.Builder dataMsgBuilder = DataMsgProto.newBuilder();//重复二
    dataMsgBuilder.setB(b.build());
    responseMsgBuilder.setDataMsg(dataMsgBuilder.build());//重复三
    responseMsgBuilder.setA(a.build());
    sendMsgToClient(channel, responseMsgBuilder.build());//重复四
message SC_ResponseMsgProto {

    optional DataMsgProto                  dataMsg                  = 1;
    optional A                              a                       = 2;


    message DataMsgProto {
       optional B              b              = 1;
    }
    
    message A {
       optional int32              num             = 1;
       optional C                  c               = 2;
    }

     message B {
          optional int32              num             = 1;
     }

     message C {
         optional int32              num             = 1;
    }
}

项目客户端和服务器采用的是Google的protobuf协议,数据结构设计采用的是森林结构。如上所示,SC_ResponseMsgProto是最顶层对象,在最顶层对象下有多个不同类别的子对象,如A、B、C,子对象下还拥有一些不同类别的子对象C,最终成为一个森林结构,森林里每个根对象都是一颗树。对象间有时有一些引用关系,比如,A对象使用了C引用。这样的设计在开发中是比较常见的,但是我们在项目中使用时比较流水账,大量的顶层对象代码在不同地方重复出现在项目中。对于每个程序员员来说,避免重复代码是大家都想做的。于是我大约花了不到30行代码来避免以上标注的四个重复地方,代码如下:

    /**
     * 下发给客户端的消息
     */
    private final LinkedList<GeneratedMessageLite> responseMsgs = new LinkedList<>();
    
    //添加消息
    public void putMsg(GeneratedMessageLite msg) {
        synchronized (responseMsgs) {
            responseMsgs.add(msg);
        }
    }
    
    //发送消息
    public void sendMsg(Channel channel) {
        //和客户端通讯的数据
        SC_ResponseMsgProto.Builder responseMsgBuilder = SC_ResponseMsgProto.newBuilder();
        DataMsgProto.Builder dataMsgBuilder = DataMsgProto.newBuilder();
        try {
            for (GeneratedMessageLite messageLite : responseMsgs) 
            {
               if (messageLite instanceof A) {
                    responseMsgBuilder.setA((A) messageLite);
                } else if(messageLite instanceof B) {
                    dataMsgBuilder.setB((B) messageLite);
                }
                responseMsgBuilder.setDataMsg(dataMsgBuilder.build());
            }
            sendMsgToClient(channel, responseMsgBuilder.build());
        }catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
        } finally {
            responseMsgs.clear();
        }
        
    }

    //优化后代码
    role.putMsg(a.build());
    role.putMsg(b.build());
    role.sendMsg(channel);

虽然避免了重复代码,但是细心的童鞋可能发现在sendMsg()里意外的出现了不是最顶层对象的DataMsgProto.如果当DataMsgProto里出现相同类型的b、b1对象时,那就无法从类型上去区分它们了。我想到的解决方案是使用自定义唯一key来区分或者在定义协议时不允许出现相同类型的(这里并不推荐,毕竟有时候多个类型能解决不少问题)。

有同学可能会想能否使用变量名字b作为唯一区分标识,但是Java能否获取变量的名字?答案是不能的。详细参考R大在知乎上的回答

message DataMsgProto {
    optional B              b              = 1;
    optional B              b1             = 2;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 《裕语言》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 10...
    叶染柒丶阅读 28,253评论 5 19
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 174,615评论 25 709
  • 很久以前,年是一只猛兽,会从深山峡谷奔向千家万户,抢夺人类的食物,毁坏连街的房屋,甚至残杀生命,所到之处繁华转眼间...
    书生亦百用阅读 319评论 2 1
  • 十点十五分,我才从利通广场的大厦走出来。担心错过了B8的最后一班车,用手机百度查一下还有哪条路线可以回家,发现B8...
    黄青海阅读 538评论 6 6
  • carolineyty阅读 363评论 0 0