目录
小兵-规则匹配
package org.geekbang.time.spark.Reflect;
import org.springframework.beans.BeanUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ReflectTest {
public static void main(String[] args) {
// 获取场景对应规则
Rule rule = getRuleByScene("someScene");
// 获取小兵
Batman batman = getBatman();
// 获取规则对应的条件列表
List<Condition> conditionList = rule.getConditionList();
// 小兵-规则匹配
boolean matchRule = false;
switch (RuleTypeEnum.getByCode(rule.getRuleType())) {
case SIMPLE:
Condition condition = conditionList.get(0);
matchRule = isMeetCondition(condition, Batman.class, batman);
break;
case AND:
matchRule = conditionList.stream().allMatch(con -> isMeetCondition(con, Batman.class, batman));
break;
case OR:
matchRule = conditionList.stream().anyMatch(con -> isMeetCondition(con, Batman.class, batman));
break;
case EXPRESSION:
// 解析expression
break;
}
if (matchRule) {
// 向小兵发送 biu biu biu ~
}
}
/**
* 通过反射获取object的指定属性【condition.getPropertyKey()】的值
* 与condition的属性值做比较
* 即:小兵的属性是否与规则中条件的属性一致
*/
private static <T> boolean isMeetCondition(Condition condition, Class<T> tClass, T object) {
return locateObject(object, tClass, condition.getPropertyKey(), condition.getPropertyValue());
}
/**
* 定位服务,如果目标小兵<T object>通过反射获取的实际属性与
* 目标属性targetPropertyValue一致,
* 则该小兵为目标小兵
*/
public static <T> boolean locateObject(T object, Class<T> tClass,
String propertyKey, Object targetPropertyValue) {
boolean match = false;
// Object realPropertyValue = getRealPropertyValue(object,tClass);
String methodName = "get" + propertyKey.substring(0, 1).toUpperCase()
+ propertyKey.substring(1);
try {
//
/**
* 常规获取Method方式
* 通过getDeclaredMethod反射获取Method较为消耗性能,每次调用都要重新进行一次类加载
*/
// Method method = tClass.getDeclaredMethod(methodName, null);
/**
* 使用BeanUtils增加缓存机制进行优化
*/
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(tClass, propertyKey);
Method method = descriptor.getReadMethod();
// 让object对象调用自己的method方法,返回方法处理结果
Object realPropertyValue = method.invoke(object);
match = Objects.equals(targetPropertyValue, realPropertyValue);
} catch (Exception e) {
e.printStackTrace();
}
return match;
}
private static Method getRealMethod(Class tClass, String propertyKey) throws NoSuchMethodException {
String methodName = "get" + propertyKey.substring(0, 1).toUpperCase()
+ propertyKey.substring(1);
return tClass.getDeclaredMethod(methodName, null);
}
/**
* Mock 规则
*/
private static Rule getRuleByScene(String someScene) {
List<Condition> conditionList = new ArrayList<>();
Condition condition1 = new Condition(1, "有红Buff", "rune", "red");
Condition condition2 = new Condition(2, "有魔抗", "armor", "magic-defend");
conditionList.add(condition1);
conditionList.add(condition2);
Rule rule = new Rule();
rule.setRuleType("and");
rule.setConditionList(conditionList);
return rule;
}
/**
* Mock 小兵
*/
private static Batman getBatman() {
Batman batman = new Batman();
batman.setRune("red");// 有红Buff
batman.setArmor("magic-defend");// 有魔抗
return batman;
}
enum RuleTypeEnum {
SIMPLE("simple"),// 单一条件
AND("and"),// 多条件同时满足
OR("or"),// 多条件满足任一条
EXPRESSION("expression");// 条件匹配表达式
private String code;
RuleTypeEnum(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public static RuleTypeEnum getByCode(String code) {
for (RuleTypeEnum typeEnum : values()) {
if (code.equals(typeEnum.getCode())) {
return typeEnum;
}
}
return null;
}
}
}
小兵表
package org.geekbang.time.spark.Reflect;
import java.util.Map;
public class Batman {
private long id;
private String rune;//符文
private String armor;//盔甲
private String shovel;//铲子
private Map<String,String> magicArts;//法术
// get/set
}
规则表
package org.geekbang.time.spark.Reflect;
import java.util.List;
/**
* 规则表
*/
public class Rule {
// 规则类型:simple/and/or/expression
private String ruleType;
// 条件列表
private List<Condition> conditionList;
// get/set
}
条件表
package org.geekbang.time.spark.Reflect;
/**
* 条件表
*/
public class Condition {
private Integer id;
private String name;
private String propertyKey;
private String propertyValue;
public Condition(Integer id, String name, String propertyKey, String propertyValue) {
this.id = id;
this.name = name;
this.propertyKey = propertyKey;
this.propertyValue = propertyValue;
}
//get/set
}