一般使用枚举的普通用法就是switch case,但其类型一旦多起来也不太方便不便维护。
使用实现接口的方式可以达到类似工厂模式一样的自动装配体验。
假定需求:要求从配置文件读取时间配置如“1年”、“5天”或“2周”等数据,取出以当前时间为基准的“1年前”或“1月前”的某某数据。
定义一个日期单位枚举。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public enum DatePicker {
H("小时"),
D("天"),
W("周"),
M("月"),
Y("年"),
;
final private String cn;
}
此时从配置文件读取对应配置例如1y,意为“一年”,计算“一年前”的时间节点。
switch case方式计算
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
46
47
48
49
50
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import io.github.youthred.es.cleaner.common.DatePicker;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
class EnumTest {
@Test
void before() {
String before = "1y";
String dateUnitName = StrUtil.sub(StrUtil.reverse(before), 0, 1).toUpperCase();
int num = Integer.parseInt(StrUtil.sub(before, 0, -1));
try {
DatePicker datePicker = DatePicker.valueOf(dateUnitName);
LocalDateTime beforeTimePoint;
switch (datePicker) {
case H:
beforeTimePoint = LocalDateTime.now().minusHours(num);
break;
case D:
beforeTimePoint = LocalDateTime.now().minusDays(num);
break;
case W:
beforeTimePoint = LocalDateTime.now().minusWeeks(num);
break;
case M:
beforeTimePoint = LocalDateTime.now().minusMonths(num);
break;
case Y:
beforeTimePoint = LocalDateTime.now().minusYears(num);
break;
default:
throw new IllegalArgumentException("不支持的枚举类型:" + datePicker);
}
log.info("此时 {},读取 {} 之前也就是 {} 之前(含)的数据",
LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)),
num + datePicker.getCn(),
beforeTimePoint.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN))
);
} catch (IllegalArgumentException e) {
log.error("单位 {} 转化DatePicker枚举失败:{}", dateUnitName, ExceptionUtil.getSimpleMessage(e));
}
}
}
执行结果
1
INFO-2022-05-20 15:32:58-[main]-EnumTest:此时 2022-05-20 15:32:58,读取 1年 之前也就是 2021-05-20 15:32:58 之前(含)的数据
若是枚举类型新增,那switch case代码块里也需要跟着新增对应代码,这样比较繁琐且代码耦合。
改为实现接口的方式。
- 定义接口
1
2
3
4
5
6
import java.time.LocalDateTime;
public interface Before {
LocalDateTime minus(long num);
}
- 枚举实现该接口
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
46
47
48
49
50
51
52
53
54
package io.github.youthred.es.cleaner.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public enum DatePicker implements Before {
H("小时") {
@Override
public LocalDateTime minus(long num) {
return LocalDateTime.now().minusHours(num);
}
},
D("天") {
@Override
public LocalDateTime minus(long num) {
return LocalDateTime.now().minusDays(num);
}
},
W("周") {
@Override
public LocalDateTime minus(long num) {
return LocalDateTime.now().minusWeeks(num);
}
},
M("月") {
@Override
public LocalDateTime minus(long num) {
return LocalDateTime.now().minusMonths(num);
}
},
Y("年") {
@Override
public LocalDateTime minus(long num) {
return LocalDateTime.now().minusYears(num);
}
},
;
final private String cn;
public static List<String> names() {
return Arrays.stream(values())
.map(DatePicker::name)
.collect(Collectors.toList());
}
}
每个类型的实现代码是省不了的,但这样可以很好地解耦,且易于维护。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
void beforeByInterface() {
String before = "1y";
String dateUnitName = StrUtil.sub(StrUtil.reverse(before), 0, 1).toUpperCase();
int num = Integer.parseInt(StrUtil.sub(before, 0, -1));
try {
DatePicker datePicker = DatePicker.valueOf(dateUnitName);
// 消灭 switch case
LocalDateTime beforeTimePoint = datePicker.minus(num);
log.info("此时 {},读取 {} 之前也就是 {} 之前(含)的数据",
LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)),
num + datePicker.getCn(),
beforeTimePoint.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN))
);
} catch (IllegalArgumentException e) {
log.error("单位 {} 转化DatePicker枚举失败:{}", dateUnitName, ExceptionUtil.getSimpleMessage(e));
}
}