辅助创建对象工具
我们编写代码时有些时候需要编写组装比较复杂的参数,写起来,非常麻烦,我以前使用的一次mapstruct,想按照它的思路写一个编译时组件处理器,但是对于级联属性的赋值,在编译时无法获取详细信息,最终只能求助于运行时注解
实际也非常简单,就是使用反射创建对象,并对对象的级联属性赋值,若对象没有创建自动创建,我在此基础上又使用责任链与代理模式,把对象的创建逻辑,类型转换逻辑给抽取出来了
效果:
隔空传参
你是否遇到这样的问题,A创建B,B创建C,但是C需要A的参数,B虽然不需要但是还是要使用构造器或set传递这些参数,使用构造器传参会使对象创建代码非常不美观,set又容易忘记调用,并且最重要的是B不需要这个参数,这个参数对B是冗余的,这时可能有些人会想着IOC容器,但是容器中的对象并没有对象生命周期的范围,A被创建多次,C中所需的参数可能是专属自己A中的参数。于是我便想,使用发布参数的形式,父对象(例如A)发布参数,子对象(例如C)接受参数。
我使用ThreadLocal做了简单的实现
效果:
这样的实现明显是有问题的,但是我暂时也没有什么好方法,但是我认为若它能被好好的实现,一定能对编程带来巨大的便利
补充
后来我发现通过Reflection.getCallerClass获取调用该方法的类信息(类似获取方法调用堆栈)可以解决一些问题
private static void setValue(Object obj, Field field, String name) {
int deep=3;//从非框架代码开始
Class<?> clazz=Reflection.getCallerClass(deep);//获取调用它的类
while (clazz!=null){
Map<String, Object> map = MAP_MAP.get(clazz);
if(map!=null&&map.containsKey(name)){
field.setAccessible(true);
field.set(obj,map.get(name));
return;
}else {
deep++;
clazz=Reflection.getCallerClass(deep);
}
}
throw new RuntimeException("对象"+obj+"没有找到");
}
2021-12-24
我突然想到隔空传参可以使用发布订阅递归的方式,于是又写了两版
方案1,使用属性共享接受参数
方案2,通过发布接受传递数据
这样一来实际跟安卓的EventBus或Spring消息机制类似了
最后还是直接使用反射简单省事
public class Reflect {
public static <T> T getValue(Object target, String exp){
String[] exps = exp.split("\\.");
for (int i = 0; i < exps.length; i++) {
if(target==null){
return null;
}
target=move(target,exps[i],false);
}
return (T) target;
}
/**
* @param target 目标对象
* @param exp 表达式
* @param value 设置的值
* @param create 是否在对象不存在时自动创建
*/
@SneakyThrows
public static void setValue(Object target, String exp, Object value, boolean create){
String[] fields = exp.split("\\.");
int last=fields.length-1;
for (int i = 0; i < last; i++) {
if(target==null){
return;
}
target=move(target,fields[i],create);
}
if(target!=null){
Field field = target.getClass().getDeclaredField(fields[last]);
field.setAccessible(true);
field.set(target,value);
}
}
@SneakyThrows
private static Object move(Object target, String fieldName, boolean create) {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object res = field.get(target);
if(create&&res==null){
res=field.getType().newInstance();
field.set(target,res);
}
return res;
}
public static void setValue(Object target,String exp,Object value){
setValue(target, exp, value,false);
}
}