程序员偷懒第一式——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

--------------------------------------2022年1月13日------------------------------------------

工作了这么多年之后,知道了 lombak。使用该插件可直接生成@builder 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值