欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

程序员偷懒第一式——POJO托管

程序员文章站 2022-06-15 10:13:15
...

背景:在写业务系统的时候,常会写到这样的语句。

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



相关标签: 反射 POJO