「重构」手把手教你重构一段烂代码之“见名知意”

「重构」手把手教你重构一段烂代码之“见名知意”

首页冒险解谜代码重构更新时间:2024-05-07

话不多说,直接上这次要重构的目标:

public class Application { private List<int[]> theList; ... // 本次需要重点关注的代码 public List<int[]> getThem() { List<int[]> list1 = new ArrayList<>(); for (int[] x : theList) { if (x[0] == 4) { list1.add(x); } } return list1; } }代码的坏味道

这是一段很短且真实逻辑并不复杂的代码,但是从这段小小的代码里面,我们却嗅到了不少坏味道:

总结来说:代码缺乏好的命名,无法让阅读者根据名字(函数名、变量名)来了解函数总体的逻辑。

第一步重构

如果把代码改成下面这个样子,或许会好一点:

public class Application { private static final int FLAGGED = 4; private static final int STATUS_VALUE_INDEX = 0; private List<int[]> gameBoard; ... public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<>(); for (int[] x : gameBoard) { if (x[STATUS_VALUE_INDEX] == FLAGGED) { flaggedCells.add(x); } } return flaggedCells; } }

在这一步的重构中,我们仅仅是修改了函数名、变量名,定义出了常量。其中:

相信你看到这段代码,对它的作用已经能猜个七七八八了:

这大概是一个棋盘类游戏,棋盘由一个个格子构成,每个格子用一个int数组来表示。之所以用数组,是因为格子所包含的信息很多,比如颜色、值等等。其中,0这个下标代表格子的状态信息。如果被标记(flagged)过,数值为4。

第二步重构

接下来,用面向对象的思想,再把一些信息“封装”一下。

public class Application { private List<Cell> gameBoard; public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<>(); for (Cell cell : gameBoard) { if (cell.isFlagged()) { flaggedCells.add(cell); } } return flaggedCells; } private static class Cell { private static final int FLAGGED = 4; private static final int STATUS_VALUE_INDEX = 0; private int[] info; ... private boolean isFlagged() { return info[STATUS_VALUE_INDEX] == FLAGGED; } } }

在这一步,通过定义Cell这个类(实际上不需要是内部类),部分实现细节屏蔽掉了。

上层应用不需要关注Cell内部是如何存储各种信息的,当前依然保留了int[]作为底层实现,但是数组是一种比较裸的用法,后续完全可以替换为更好的形式。

Cell提供了isFlagged方法,让上层应用可以只关心是否标记这样的业务逻辑,而不需要关注4和0这样的实现细节。

实际上有了这些之后,可通过Lambda表达式把getFlaggedCells化简到一行,你知道怎么做吗?

总结

Phil Karlton说:

There are only two hard things in Computer Science: cache invalidation and naming things

大家平时都在讲工匠精神,有时候,匠心的体现并不需要多么花里胡哨的炫技,只需要好好的给代码取个见名知意的名字,或许就已经成功了一半。


说明:因为之前写的各种文章阅读量实在过于惨淡,所以这是一个新开的、比较偏实操一些的系列。其中代码的例子来自于《Clean Code》,文字部分为原创内容。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved