避免啰嗦,不要多此一举!

看到一段代码,写的比较啰嗦就用GitHub Copilot简化了一下,简化结果很简单,复杂度从273%降低到13%(复杂度使用IDEA插件 Better Highlights )。代码行数从79行变成了29行,下面是原始代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static boolean comparelogic(String condition, String value, String ccompare) {
try {
if ("0".equals(ccompare)) {//包含
if (condition.contains(value)) {
return true;
} else {
return false;
}
}
if ("1".equals(ccompare)) {//不包含
if (!condition.contains(value)) {
return true;
} else {
return false;
}
}
//省略2,3,4,5,6,7,8,9
return false;

} catch (Exception e) {
return false;
}
}

第一眼看到下面代码就觉得很啰嗦:

1
2
3
4
5
if (condition.contains(value)) {
return true;
} else {
return false;
}

直接写 return condition.contains(value); 即可,不要判断true时返回true,否则false。你的判断条件和返回结果一致时,直接返回判断条件即可。

除此之外本来互斥的多个if 写成了独立的,连 else if 都没使用,如果 ccompare="9" 所有 if 条件都要判断一遍才能走到最后一个符合条件的 if

另外这么典型的排比句,用 switch 是最合适的,经过优化后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static boolean comparelogic(String condition, String value, String ccompare) {
try {
switch (ccompare) {
case "0": //包含
return condition.contains(value);
case "1": //不包含
return !condition.contains(value);
case "2": //等于
return condition.equals(value);
case "3": //不等于
return !condition.equals(value);
case "4": //大于
return new BigDecimal(condition).compareTo(new BigDecimal(value)) > 0;
case "5": //大于等于
return new BigDecimal(condition).compareTo(new BigDecimal(value)) > -1;
case "6": //小于
return new BigDecimal(condition).compareTo(new BigDecimal(value)) < 0;
case "7": //小于等于
return new BigDecimal(condition).compareTo(new BigDecimal(value)) < 1;
case "8": //为空
return StringUtils.isBlank(condition);
case "9": //不为空
return StringUtils.isNotBlank(condition);
default:
return false;
}
} catch (Exception e) {
return false;
}
}

这样就足够了,当考虑 condition 可能扩展更多比较方式时,还可以考虑策略模式,如果不会变化就不要选择策略模式,几乎所有设计模式都会让类的数量爆炸式增长,这里直接给出 Copilot 的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public interface ComparatorStrategy {
boolean compare(String condition, String value);
}

public class ContainsComparator implements ComparatorStrategy {
@Override
public boolean compare(String condition, String value) {
return condition.contains(value);
}
}

public class NotContainsComparator implements ComparatorStrategy {
@Override
public boolean compare(String condition, String value) {
return !condition.contains(value);
}
}

// ... 其他比较策略的实现

public class CompareLogic {
private static final Map<String, ComparatorStrategy> strategies = new HashMap<>();

static {
strategies.put("0", new ContainsComparator());
strategies.put("1", new NotContainsComparator());
// ... 其他比较策略的实例
// TODO 增加其他实现仍然需要改这里代码
}

public static boolean comparelogic(String condition, String value, String ccompare) {
ComparatorStrategy strategy = strategies.get(ccompare);
if (strategy == null) {
return false;
}
return strategy.compare(condition, value);
}
}

上面的方式消除了 ifswitch,但是别听信哪些为了消除 if 推荐这么做的文章,如果你有扩展 变化 的需求,这种方式很方便,附带消除了 if。上面这个方案再配合有 IOC 注入的框架时,下面注册的代码可以去掉,做到完全不需要改动任何代码:

1
2
3
4
5
6
static {
strategies.put("0", new ContainsComparator());
strategies.put("1", new NotContainsComparator());
// ... 其他比较策略的实例
// TODO 增加其他实现仍然需要改这里代码
}

下面是基于Spring框架实现策略模式的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class CompareLogic {
private final Map<String, ComparatorStrategy> strategies;

@Autowired
public CompareLogic(ApplicationContext applicationContext) {
strategies = applicationContext.getBeansOfType(ComparatorStrategy.class);
}

public boolean comparelogic(String condition, String value, String ccompare) {
ComparatorStrategy strategy = strategies.get(ccompare);
if (strategy == null) {
return false;
}
return strategy.compare(condition, value);
}
}

//其中一个实现
import org.springframework.stereotype.Component;

@Component("0")
public class ContainsComparator implements ComparatorStrategy {
@Override
public boolean compare(String condition, String value) {
return condition.contains(value);
}
}

//其中一个实现
import org.springframework.stereotype.Component;

@Component("1")
public class NotContainsComparator implements ComparatorStrategy {
@Override
public boolean compare(String condition, String value) {
return !condition.contains(value);
}
}

配合 IOC 使用时,像上面两个实现这样扩展就能增加新的策略,运行时扫描到就会自动注册,做到真正不修改任何代码,直接扩展新策略。

上面这个是 Copilot 给出的实现,比我常用的方式更简单,我没想到的地方是 @Component("1") 中指定的名字,使用 getBeansOfType 可以直接返回名字作为 key,实例作为 value 的 Map。我以前会增加一个接口方法来返回策略名称,然后注入 List<接口> ,遍历放到 Map 中,没想到 Copilot 给出了一个更简单的实现!又学到了。


避免啰嗦,不要多此一举!
https://blog.mybatis.io/post/20240606.html
作者
Liuzh
发布于
2024年6月6日
许可协议