说起代码整洁之道,想必大家想到更多的是那本经典重构书籍。没错,记得当时自己读那本书的时候,一边结合项目实战,一边结合书中的讲解,确实学到了很多东西,对我自己的编码风格影响极深。随着时间的流逝,书中很多具体的内容自己都记得不太清楚,但是会不自觉的应用到实际工作中,相当于成为自己的一种编码习惯了。所以在这篇博客里面,我将结合自己最近在android项目里面重构的经历,分享一些自己的代码重构体会吧,希望能够总结自己,同时帮到大家。
我记得以前遇到一个team leader他给我很深刻的影响就是人很自负,但是不得不承认技术很牛。他给我印象最深的一句话就是:你在写代码的时候,对自己的要求就是一个方法里面,最多不能够超过20-30行代码,不然我就认为你这个代码写的很烂,需要考虑重构了。从此我就深深得被他那句话给震撼到了,这句话以后一直就作为我编码时候的座右铭。好了,让我们回到正题上来吧,请看如下代码:
private void setDownGoodsListView() { downGoodsListAdapter = new RsvAdapter(recyclerViewBelow.getContext(), downGoodsList, R.layout.goodsitem2); recyclerViewBelow.setAdapter(downGoodsListAdapter); downGoodsListAdapter.setItemClickListener(new RsvAdapter.ItemClickListener() { @Override public void onItemClick(View view, int position) { TrackPart currentTrack = SvmFactory.getSvm().getTrackPart(); if (currentTrack.canSell(goodsId, isHotDrank)) { Bundle data = new Bundle(); data.putString("GoodsId", goodsId); data.putBoolean("GoodsIsHot", isHotDrank); Context context = view.getContext(); Intent intent = new Intent(context, SaleActivity.class); intent.putExtras(data); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } } @Override public void onItemLongClick(View view, int position) { } }); }
private void setUpGoodsListView() { upGoodsListAdapter = new RsvAdapter(recyclerViewTop.getContext(), upGoodsList,R.layout.goodsitem); recyclerViewTop.setAdapter(upGoodsListAdapter); upGoodsListAdapter.setItemClickListener(new RsvAdapter.ItemClickListener() { @Override public void onItemClick(View view, int position) { TrackPart currentTrack = SvmFactory.getSvm().getTrackPart(); if (currentTrack.canSell(goodsId, isHotDrank)) { Bundle data = new Bundle(); data.putString("GoodsId", goodsId); data.putBoolean("GoodsIsHot", isHotDrank); Context context = view.getContext(); Intent intent = new Intent(context, SaleActivity.class); intent.putExtras(data); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } } @Override public void onItemLongClick(View view, int position) { } }); }
上面这段代码是我从最近的android项目里面截取出来两个方法,具体含义你可以理解为:有两个列表,同时绑定数据和绑定每一个item的点击事件。如果你拿到这段代码,你会怎样去重构呢?
也许聪明的你,很快就能够发现这段代码最大的问题就是冗余代码太多,有没有发现itemClick里面的代码,除了goodsId/isHot两个参数差别之外,基本全部都是一样的代码。基于上面的分析,我们可以将代码进行如下重构:
private void setUpGoodsListView() { upGoodsListAdapter = new RsvAdapter(recyclerViewTop.getContext(), upGoodsList,R.layout.goodsitem); recyclerViewTop.setAdapter(upGoodsListAdapter); upGoodsListAdapter.setItemClickListener(new RsvAdapter.ItemClickListener() { @Override public void onItemClick(View view, int position) { clickGoodsItemAction(view,upGoodsList.get(position).getId(),upGoodsList.get(position).isHot()); } @Override public void onItemLongClick(View view, int position) { } }); }
private void setDownGoodsListView() { downGoodsListAdapter = new RsvAdapter(recyclerViewBelow.getContext(), downGoodsList, R.layout.goodsitem2); recyclerViewBelow.setAdapter(downGoodsListAdapter); downGoodsListAdapter.setItemClickListener(new RsvAdapter.ItemClickListener() { @Override public void onItemClick(View view, int position) { clickGoodsItemAction(view,downGoodsList.get(position).getId(),downGoodsList.get(position).isHot()); } @Override public void onItemLongClick(View view, int position) { } }); }
private void clickGoodsItemAction(View view,String goodsId,boolean isHotDrank){ TrackPart currentTrack = SvmFactory.getSvm().getTrackPart(); if (currentTrack.canSell(goodsId, isHotDrank)) { Bundle data = new Bundle(); data.putString("GoodsId", goodsId); data.putBoolean("GoodsIsHot", isHotDrank); Context context = view.getContext(); Intent intent = new Intent(context, SaleActivity.class); intent.putExtras(data); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } }
可以看到,我们进行了冗余重构之后,整个代码就简洁、直观了很多。但是如果只重构到这一步的话,那么还不是很完美的代码。你也许会问,还有什么地方可重构的吗?这个时候我们可能还需要用到另外一个重构原则就是:一个方法里面尽量只做一件事情。这下你就应该能够明白接下来应该做的事情了吧?首先让我们来看看,两个set开头的方法里面到底都干了几件事情?第一件事情就是:绑定列表数据;第二件事情就是设置每一个item的点击事件;好吧,分析到这里接下来的重构就是顺理成章的事情了,set方法重构之后的代码如下:
private void setUpGoodsListView() { setOneAdapter(); setOneItemClick(); }
private void setDownGoodsListView() { setTwoAdapter(); setTwoItemClick(); }
private void setOneAdapter(){ upGoodsListAdapter = new RsvAdapter(recyclerViewTop.getContext(), upGoodsList,R.layout.goodsitem); recyclerViewTop.setAdapter(upGoodsListAdapter); }
private void setOneItemClick(){ upGoodsListAdapter.setItemClickListener(new RsvAdapter.ItemClickListener() { @Override public void onItemClick(View view, int position) { clickGoodsItemAction(view,upGoodsList.get(position).getId(),upGoodsList.get(position).isHot()); } @Override public void onItemLongClick(View view, int position) { } }); }
同理连个two方法也是这样去拆分,这里就不一一贴出来了。重构到这里,你会发现整个代码结构就一目了然,但是我故意犯了个很二的错误,那就是命名规范的问题。这个也许大家都很清楚:每个变量的命名,每个方法的命名都尽量要让人家一看到这个名字就知道该方法是干什么的?所以这里可能又牵涉到一个很有意思的矛盾问题(鸡生蛋,还是蛋生鸡呢?)。也就是在我们代码里面到底是应该加注释呢?还是尽量少加注释呢?你会看到只要我们遵循命名释意的规则,我们就不需要去添加注视了,因为项目结构随时在变,很可能今天添加的注释,明天就不准了,这样的注释有比没有更害人。所以我的原则是能不加就不加。
好了,今天就到这里吧!其实还有更好的重构原则,大家可以参考一些书籍,下班了see you!