当前的项目在设计的时候,后台负责处理转化页面上的select值。比如,页面下拉拿到的值就是 在线/离线,后台存储为 0/1,这个映射关系,由后台维护
第一稿
项目赶进度,直接用 map 一把梭哈,就是用的时候,稍微有点蛋疼。。。
public static Map<String, Integer> robotState = new HashMap<String, Integer>() {
{
// 车辆状态:0:在线,1:离线,2:禁用,3:维护
put("在线", 0);
put("离线", 1);
put("禁用", 2);
put("维护", 3);
}
}, robotWork = new HashMap<String, Integer>() {
{
// 工作状态:1:空闲,0:运行,2:充电,4:报警
put("运行", 0);
put("空闲", 1);
put("充电", 2);
put("报警", 3);
}
}
// 下边还有一大堆。。。
.........
不是很优雅,对吧。而且,这些都是可以修改的,万一哪天有傻x给我偷偷使绊子改了我定义的值呢?
public static String get(Map<String, Integer> map, Integer val) {
for (String key : map.keySet()) {
if (map.get(key) == val) {
return key;
}
}
return map.keySet().iterator().next();
}
public static Integer get(Map<String, Integer> map, String key) {
val = map.get(key);
if (val != null) {
return val;
}
return map.values().iterator().next();
}
提供了两个静态的 get(),需要指定使用的哪个map,然后拿 key(或value) 换 value(或key),程序调用的方式 SelectVal.get(robotState, 1);
第二稿
将 map 数据,转化为枚举类,有一个要求就是,要根据给定的 key或 value,去换取另一个值
因为所有的枚举类,都要有这两个功能,规范起见,定义一个接口,提供两个默认实现,简化枚举类的定义
public abstract class EnumVal {
default Integer get(Enum<? extends EnumVal> e, String val) {
for (EnumVal ev : e.getDeclaringClass().getEnumConstants()) {
if (ev.getStr().equals(val))
return ev.getNum();
}
return 0;
}
default String get(Enum<? extends EnumVal> e, int val) {
for (EnumVal ev : e.getDeclaringClass().getEnumConstants()) {
if (ev.getNum() == val)
return ev.getStr();
}
return "";
}
String getStr();
Integer getNum();
}
然后枚举类就成了这个样子:
@AllArgsConstructor
@Getter
public enum StationState implements EnumVal {
ON( "在线",0),
OFF("离线",1),
FORBID( "禁用",2),
FIX("维护",3);
private String str;
private Integer num;
private static StationState instance() {return ON; }
public static String get(Integer val) {
return instance().get(instance(), val);
}
public static Integer get(String val) {
return instance().get(instance(), val);
}
}
emmm,最后的两个静态方法定义的是不是蠢了一点,需要手动给一个实例,然后通过这个实例去调接口上的 default 方法,可是,没有实例的话,那 default 方法就没法调用了啊,太难了
第三版
最近在看 java的泛型,突然一个抖机灵,发现,我可以吧枚举类上的方法调用,改为委托调用???就是我吧这操作的逻辑,扔到另一个公共类上,然后只需要在枚举类中提供两个静态方法,然后只需要在静态方法里访问公共类里的具体操作,这个不就是代理的感觉嘛
开整,在那个接口类中,定义一个包访问权限的公共类
public interface EnumVal {
String getStr();
Integer getNum();
}
class EnumValFunc {
public static String getVal(Class<? extends EnumVal> clz, int val) {
for (EnumVal ev : clz.getEnumConstants()) {
if (ev.getNum() == val)
return ev.getStr();
}
return "";
}
public static int getVal(Class<? extends EnumVal> clz, String val) {
for (EnumVal ev : clz.getEnumConstants()) {
if (ev.getStr().equals(val))
return ev.getNum();
}
return 0;
}
}
然后,枚举类中的静态方法调用,就变成了这:
public static String getVal(int val) {
return EnumValFunc.getVal(CURR_CLZ_NAME, val);
}
public static int getVal(String val) {
return EnumValFunc.getVal(CURR_CLZ_NAME, val);
}
// 通过创建匿名类的方式,获取当前的className
@SuppressWarnings("unchecked")
private static final Class<? extends EnumVal> CURR_CLZ_NAME = (Class<? extends EnumVal>) new Object() {}.getClass().getEnclosingClass();
怎么样,是不是看着特别舒服了,复制粘贴的时候,只需要修改下具体的枚举值就行
改到这里,发现那2个静态的方法,每次定义一个新的枚举类,都要抄一遍,略微有些嫌弃吧,觉得代码重复,但这个静态调用,确实对代码编写的体验还是很不错的,然后,折腾着,小改一版。。。
第三版 ’2
大致思路就是,去掉那个枚举操作的公共类,吧方法改回为接口的default方法,然后在枚举类中定义一个静态的 getInstance(),需要在接口中补充一个一个方法 getClz()
package com.rlzz.r9.po.visitor.enu;
public interface EnumVal {
public default String getVal( int val) {
for (EnumVal ev : getClz().getEnumConstants()) {
if (ev.getNum() == val)
return ev.getStr();
}
return "";
}
default int getVal( String val) {
for (EnumVal ev : getClz().getEnumConstants()) {
if (ev.getStr().equals(val))
return ev.getNum();
}
return 0;
}
Class<? extends EnumVal> getClz();
String getStr();
Integer getNum();
}
枚举类中的方法就变成了这个样子:
public static EnumVal getInstance() {
return CURR_CLZ_NAME.getEnumConstants()[0];
}
@Override
public Class<? extends EnumVal> getClz() {
return CURR_CLZ_NAME;
}
// 通过创建匿名类的方式,获取当前的className
@SuppressWarnings("unchecked")
private static final Class<? extends EnumVal> CURR_CLZ_NAME = (Class<? extends EnumVal>) new Object() {}.getClass().getEnclosingClass();
emmmm,这改完后,代码量没啥变化,反而调用的时候,要先通过 getInstance()获取实例再操作,多了一步,似乎更麻烦了些。。。
先不管了吧,两种方案看着都差不多,过两天说不定能想明白点
其实,我突然想到了通过类实例调用的优势,那就是,如果我的通用方法要是有所变化,比如,要扩展的话,只需要在接口里加个 default 的方法就完事;前一种的话,就需要回过头去每个枚举类中补充新的静态方法
就先写到这里吧
--------------------------------------- 2020/10/19 ---------------------------------------
后续
吧全部的 map数据翻译成枚举类,代码里其他的地方都还没跟着变,复制粘贴再改改,枚举实例命全靠有道翻译。看着多出来的几十个枚举类,陷入沉思,我是个憨批吗???这工作量明明大了好多嘛,淦。整完发现还是 map 的方式香。。。
刚好看到 java11的新特性,不可变集合类??!刚好解决map数据可能被修改的情况
尝试在 java8 里嗦一哈
不错,当前项目刚好引用了谷歌提供的集合工具,不可变map中有一个方法刚好合适:
ImmutableMap.copyOf(Map<? extends K, ? extends V>)
现在的map声明就变成了:
public static Map<String, Integer> robotState = ImmutableMap.copyOf(new HashMap<String, Integer>() {
{
put("在线", 0);
put("离线", 1);
put("禁用", 2);
put("维护", 3);
}
})
ctrl + f 批量替换补个头和尾,完事