修改对象的行为和值(代理)

文章介绍了两种处理Java对象属性值的方式:一是通过Hutool的copyProperties方法复制对象并覆盖属性;二是使用代理模式,创建代理类拦截并修改方法的返回值。后者更为灵活,实现了对对象行为的增强。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

最近遇到一个需求,需要在某个位置,统一处理对象的一些属性值:
方案有两种:

  1. 直接复制一份,将属性覆盖后,返回一个新对象
  2. 搞一个代理类,代理这个对象,修改对象的原有行为和值,从而达到修改属性值的目的

一、复制一个对象

这里有现成的hutool 方法,当然不用自己造轮子了,废话不多说,直接上代码:

这里有个类,我设置了id为12 ,我想将id属性值修改为2

public class MainTet {
   public static void main(String[] args) {

       Menu menu = new Menu();
       menu.setMenuCode("12");
       menu.setId(12);

       Map<String, Object> overrideProps = new HashMap<>();
       overrideProps.put("id", 2);

       Menu menu1 = overrideField(menu,overrideProps);
       System.out.println(JSONUtil.toJsonStr(menu1));
       System.out.println(JSONUtil.toJsonStr(menu));

   }
	private static <T> T overrideField(T menu,Map<String, Object> overrideProps) {
       Object object = BeanUtil.copyProperties(menu, menu.getClass());
       for (Map.Entry<String, Object> entry : overrideProps.entrySet()) {
           BeanUtil.setFieldValue(object, entry.getKey(), entry.getValue());
       }
       return (T) object;
   }
}
    

新建一个类的结果
可以看到,返回了新对象,然后值已经被修改,原值仍然是12;

二、代理对象

这个就不一般了,它不是新建了对象,而是创建了一个代理类,类似于spring中的代理对象,然后它不修改之前对象的属性,而是增强
大致思路:

  1. 创建代理对象
  2. 拦截方法,拦截后执行代理方法,而非原方法
public class MainTet {
   public static void main(String[] args) {

       Menu menu = new Menu();
       menu.setMenuCode("12");
       menu.setId(12);

       Map<String, Object> overrideProps = new HashMap<>();
       overrideProps.put("id", 2);

		Menu proxy = getProxy(menu,overrideProps);
        System.out.println(proxy.getId());
   }
   
   private static <T> T getProxy(T menu, Map<String, Object> overrideProps) {

        // 创建代理对象
        ProxyFactory proxyFactory = new ProxyFactory(menu);
        proxyFactory.setProxyTargetClass(Boolean.TRUE);

        Map<String, Object> overrideMap = new HashMap<>();

        // 设置代理对象的代理方法
        // 例如 key为id 那么 overrideMap 中的key为getId 和 isid
        overrideProps.forEach((k, v) -> {
            String methodName = "get" + k.substring(0, 1).toUpperCase() + k.substring(1);
            overrideMap.put(methodName, v);
            methodName = "is" + k.substring(0, 1).toUpperCase() + k.substring(1);
            overrideMap.put(methodName, v);
        });

        // 利用方法拦截器拦截调用方法,执行代理方法
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                String methodName = invocation.getMethod().getName();
                if (overrideMap.containsKey(methodName)) {
	                // 直接返回覆盖值,不执行原方法
                    return overrideMap.get(methodName);
                }
                // 执行原方法
                return invocation.proceed();
            }
        });
        return (T) proxyFactory.getProxy();
    }
}

打印结果

也被更为了2

重点来了

  • 我在Menu对的getId() 方法中打了断点,但是debug运行过程中,并不会到此处断点
    方法断点

因为,代理后,根本不会执行真正的getId 方法,而是在 MethodInterceptor的 invoke 中,根据判断,直接返回覆盖值


总结

第二种方式比较高大上,相当于手动创建了代理对象,并修改了对象的原有属性和行为!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寂寞旅行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值