很多人写代码为了快速交付,直接复制相似的代码和局部的一两行代码,并未充足考虑到未来后人如何修改这段代码,是否会给后人留坑,没有给予整个类或工程的角度审视有哪些代码是应该复用,哪些应该开辟新分支,本文以一个很简单的案例讲解避免重复代码的效果和意义。
案例:缓存读写时经常会用业务字段增加前缀去拼接一个缓存key
public FakeObj getFakeObj(Integer bizId) {
// ...
String cacheKey = "orderId:" + bizId;
// ...
}
public boolean putFakeObj(Integer bizId, FakeObj fakeObj) {
// ...
String cacheKey = "orderId:" + bizId;
// ....
}
public boolean deleteFakeObj(Integer bizId) {
// ...
String cacheKey = "orderId:" + bizId;
// ....
}
上面的代码每个方法中都有一行是用来构造缓存key的,虽然构造缓存key是一个很简单且只有一行的代码,但这个拼接缓存key的逻辑重复了3行。
这种写法有2个问题:
- 如果哪一天需要修改这个缓存key构造方式时,就需要修改3处。这种写法并不优雅
- 由于
orderId常量需要写多次,如果某一次拼写错误,则很难被发现
如果把拼接缓存key的那一行当成是一个逻辑,那么它更适合提取成一个private方法,尽管这个方法只有一行,修改后如下:
public FakeObj getFakeObj(Integer bizId) {
// ...
String cacheKey = buildFakeCacheKey(bizId);
// ...
}
public boolean putFakeObj(Integer bizId, FakeObj fakeObj) {
// ...
String cacheKey = buildFakeCacheKey(bizId);
// ....
}
public boolean deleteFakeObj(Integer bizId) {
// ...
String cacheKey = buildFakeCacheKey(bizId);
// ....
}
private String buildFakeCacheKey(Integer bizId) {
return "orderId:" + bizId;
}
虽然总行数变多了,但是代码语义更清晰了,看代码就像阅读一样。
建议
- 只要重复代码超过1处被使用,那么它就应该提取成一个方法或临时变量,并给他取一个有含义的方法名或变量名。
- 避免重复代码,是在积功德!
(如果你使用IDE,比如:idea,可以选中重复的代码,右键从refactor中选择合适的选项,让idea帮你写好代码,风险很低)