程序员偷懒第一式——POJO托管
背景:在写业务系统的时候,常会写到这样的语句。
AObject a = new AObject();
a.setId("xxx");
a.setName("xxx");
AServer.findByIdAndName(a);
明明我就只想组装一个DTO对象,非得要写那么长的代码,注意哦,这是只有两个参数的情况下。多数情况下4个以上。后来我学聪明了,我怎么写
AObject a = new AObject(){this.setId("");this.setName("")}
可是这样的代码会被sonar评定为B级代码,这么写会导致内存溢出。那到底才能如何偷懒了?
为了偷懒彻底,肯定要借助高效的工具。比如:beanUtils.copy 。
其实也可以重载多个构造方法,解决这种重复代码的问题,不过局限是,参数个数和数据类型一致,仅仅区别与参数名。这重载就做不到了。
终极偷懒第一式:其实看看beanUtils的实现方式,我们可以变通的利用java的反射机制,紧接着通过Builder或者Factory来托管POJO的实例化。调用风格再链式化,这样不管啥POJO创建都只需要一行代码。
public Obj set(String name,Object param){
...
if(field.getType() == param.getClass()){
try {
field.set(this.target,param);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
return this;
}
更新:2018年4月11日
在之前的版本中,会出现这样的bug。参入如果是目标字段的子类或者接口实现,将不会判定为同类型参数,并且只有同一个类加载器实例加载的类才会判定为同类型。旧版本代码如上。先更改为
package xxx.xxx.xxx
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Created by mmotiy on 2018/3/27.
*/
public class POJOUtil {
public static Obj build(Class clas){
return new Obj(clas);
}
static public class Obj{
private Object target;
public Obj(Class tar){
try {
this.target = tar.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Obj set(String names,Object... objects){
String[] split = names.split(",");
for(int i=split.length;i-->0;set(split[i],objects[i])){}
return this;
}
public Obj set(String name,Object param) {
//获取所有的字段
Field[] declaredFields = target.getClass().getDeclaredFields();
try{
for(Field field:declaredFields){
field.setAccessible(true);
if(field.getName().equals(name)){
//判断数据类型是否一致 判断参数类型是不是 目标类型的子类或者实现
if(isParentOrBrother(field.getType(),param.getClass())){
try {
field.set(this.target,field.getType().cast(param));
break;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return this;
}
public <T> T over(){
return (T) this.target;
}
}
/**
* 判断param是否是tar的实现
* @param tar
* @param param
* @return
*/
private static boolean isParentOrBrother(Class tar,Class param){
Class temp = param;
while(temp!=null){
if(temp.getName().equals(tar.getName())){
return true;
}
temp = temp.getSuperclass();
}
Class[] interfaces = param.getInterfaces();
for(Class itf:interfaces){
if(itf.getName().equals(tar.getName())){
return true;
}
}
return false;
}
public static void main(String[] args) {
System.out.println(build(B.class).set("ls",new ArrayList<>()).<B>over().ls instanceof List);
}
}
class A{
}
interface C{
}
class B extends A implements C{
List ls;
}
生活于此美好,做一名懂得偷懒的程序员。对码农say no。最后调用over方法,进行强转,我使用的测试环境是1.8这有可能导致,低于1.8的jdk需要手动参数T的类型,如<A>over()。
2018年4月11日 本次更新另外重载了set方法,意味着你可以一次性为多个字段复制 exp: Obj.set("a,b,c",a,b,c);
国际惯例最后贴上自己的GitHub
上一篇: JavaBeans分类
下一篇: javaweb:JavaBean及内省
推荐阅读