一、模式结构
1. 背景介绍
枚举的验证模式核心是基于接口实现而达到,当一个枚举类实现接口后,其每个元素都将需要实现接口类中定义的接口方法。基于此特性,我们即可将一个枚举定义为一类对象,而内部枚举成员则为对象的成员属性,同时由于接口实现的特性,枚举中的每个元素则需要接口类中定义的接口方法。
举个易懂的例子,程序中存在 Apple
和 Orange
两种水果,二者都包含 MEAT
与 SHAPE
两种属性,为了实现验证该属性的合法性,定义接口 Element
包含对于属性的描述方法,如名称与是否为空等等。当 Apple
枚举实现于 Element
接口,则枚举中的每个元素均需实现 Element
接口方法,即可在元素方法实现中定义验证规则。
二、代码实现
1. 接口定义
创建接口类 Element
并定义对应所需字段。
public interface Element {
String key();
String name();
boolean required();
default Object defaultValue() {
return null;
};
}
2. 枚举实现
(1) 实现一
创建枚举 AppleElement
实现于 Element
接口,此时枚举中的元素成员需实现对应接口。
public enum AppleElement implements Element {
SHAPE {
@Override
public String key() {
return "shape";
}
@Override
public String name() {
return "Apple shape";
}
@Override
public boolean required() {
return true;
}
},
MEAT {
@Override
public String key() {
return "meat";
}
@Override
public String name() {
return "Apple meat";
}
@Override
public boolean required() {
return true;
}
};
public static AppleElement get(int index) {
for (AppleElement value : AppleElement.values()) {
if (value.ordinal() == index) {
return value;
}
}
throw new IllegalArgumentException("Not found");
}
}
(2) 实现二
同理再创建一个枚举 OrangeElement
,定义方式同上。
public enum OrangeElement implements Element {
SHAPE {
@Override
public String key() {
return "shape";
}
@Override
public String name() {
return "Orange shape";
}
@Override
public boolean required() {
return true;
}
},
MEAT {
@Override
public String key() {
return "meat";
}
@Override
public String name() {
return "Orange meat";
}
@Override
public boolean required() {
return true;
}
};
public static OrangeElement get(int index) {
for (OrangeElement value : OrangeElement.values()) {
if (value.ordinal() == index) {
return value;
}
}
throw new IllegalArgumentException("Not found");
}
}
3. 验证示例
完成上述步骤后即可快速实现同源但不同类型的数据验证,相应示例如下:
public class ElementTest {
@Test
public void demo() throws Exception {
// 定义对象用于描述 Apple
var appleData = List.of(
Map.of(AppleElement.SHAPE.ordinal(), "round"),
Map.of(AppleElement.MEAT.ordinal(), "red")
);
// 定义对象用于描述 Orange
var orangeData = List.of(
Map.of(OrangeElement.SHAPE.ordinal(), "round"),
Map.of(OrangeElement.MEAT.ordinal(), "white")
);
// 验证描述信息是否符合规范
validate(appleData, AppleElement.class);
validate(orangeData, OrangeElement.class);
}
private void validate(List<Map<Integer, String>> dataList,
Class<? extends Element> aClass) throws Exception {
for (Map<Integer, String> data : dataList) {
var offset = 0;
var msg = new ArrayList<>();
for (Map.Entry<Integer, String> row : data.entrySet()) {
offset++;
var index = row.getKey();
var value = row.getValue();
// 通过反射获取枚举对应元素
Element element = (Element) aClass
.getMethod("get", int.class)
.invoke(null, index);
boolean blank = Objects.isNull(value) || Objects.equals("", value);
// 此处为验证是否为空
// 可根据业务实现更复杂逻辑
if (element.required() && blank) {
msg.add("Filed {" + element.key() + "} can't be null");
}
}
if (!msg.isEmpty()) {
// 若非法则输入信息
System.out.println(offset + ": " + msg);
}
}
}
}