结构型设计模式——代理设计模式
发布日期:2021-07-27 04:56:19
浏览次数:8
分类:技术文章
本文共 3418 字,大约阅读时间需要 11 分钟。
一、概念
代理模式Proxy,就是在访问原始的对象的时候,引入一定的简介手段,附加更多的功能,这样保证不影响原始代理核心功能的基础上可以增加额外功能(AOP思想)。
/** * 定义一个政策接口 */public interface IPolicy { /** * 执行政策方法 */ void executePolicy();}/** * 实现政策接口,进行业务逻辑处理 */public class Policy implements IPolicy { @Override public void executePolicy() { System.out.println("执行政策!"); }}
根据需求,我们在政策执行之前需要进行校验,那么我们一般的做法就是继承Policy,重写父类方法
** * 继承的方式,添加普通类型政策的校验逻辑 */public class CommonPolicy extends Policy { private String policyId; /*省略get,set方法*/ @Override public void executePolicy() { System.out.println("校验普通政策ID, 政策id = " + policyId); System.out.println("执行政策!"); }}
这样做其实是违背了“开闭原则”,虽然拓展,但对修改开放了,为了解决这个问题,我们可以采取代理模式,主要分为静态代理和动态代理
二、静态代理
代理者和原始对象继承或者遵从同一个接口,但是原始对象中值操作核心功能,而代理者则将附加功能写入,并在类内新建原始对象,然后调用其核心方法,这样就在核心功能继承上附加了额外功能,外部只需要调取代理。
/** * 改进:与Policy一样遵从同一套接口,同时将Policy实现类传入,调用其方法 * 这样可以保证对原方法的修改关闭,而增加了拓展(切面增强功能,开闭原则) * JDK代理方式 */public class SpecialPolicy implements IPolicy { private String policyId; private Policy policy; /*get\set*/ @Override public void executePolicy() { System.out.println("校验特殊政策ID, 政策id = " + policyId); policy.executePolicy(); }}
当然,我们还可以使用继承
/** * 改进:也可以使用继承来实现同样的功能(CgLib代理方式) */public class SpecialPolicy2 extends Policy { private String policyId; private Policy policy; /*get\set*/ @Override public void executePolicy() { System.out.println("校验特殊政策ID, 政策id = " + policyId); policy.executePolicy(); }}
但是这种方式还有个问题,如果政策量很大,那岂不是我的每个政策都要加一个“执行政策!”
这个业务逻辑?!
三、动态代理
本质就是利用Java反射技术将零散的目标类各个属性重组,并改写其中的方法,返回一个与原始类属性一模一样的代理类。
public class SomePolicy implements IPolicy { private String policyId; /*get/set*/ public void executePolicy() { System.out.println("政策校验,policyId = " + policyId); }}/*使用JDK反射包中的代理接口*/public class ProxyHandler implements InvocationHandler { //目标:被代理类 private Object target; public Object getProxy(Object target) { this.target = target; /** * 将目标对象传入,反射获取目标对象的类加载器、所有接口 * this=当前对象,该对象实现了InvocationHandler接口所以有invoke方法,通过invoke方法可以调用被代理对象的方法 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理类执行的方法 * @param proxy “被”代理的对象(原始对象) * @param method 需要执行的方法 * @param args 方法执行的参数 * @return * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; //AOP-before:业务增强 result = method.invoke(target, args); //AOP-after:业务增强 System.out.println("执行政策!"); return result; }}
我们测试一下:
@Testpublic void testProxyHandler() { ProxyHandler proxyHandler = new ProxyHandler(); SomePolicy somePolicy = new SomePolicy(); somePolicy.setPolicyId(UUID.randomUUID().toString()); //必须强转为接口对象,即后面somePolicy实现类的父对象 IPolicy iPolicy = (IPolicy) proxyHandler.getProxy(somePolicy); iPolicy.executePolicy();}//打印结果政策校验,policyId = 38c90df8-4dde-44ba-bacb-6990fc34bb05执行政策!
这里要注意:
1、当调用“executePolicy()
”方法的时候,其实调用的不是真正的方法,而是将方法名和参数传入到了InvocationHandler
的invoke()
方法,进行代理增强 2、进行对象强转的时候,必须转为接口对象,而不能是实现对象,否则会抛出不能同级转换的异常 java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to com.flight.carryprice.rjmodel.impl.SomePolicy
转载地址:https://blog.csdn.net/qq_45337431/article/details/101319999 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2024年09月23日 12时30分23秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
git add . git add -u git add -A区别
2019-05-27
apache下虚拟域名配置
2019-05-27
session和cookie区别与联系
2019-05-27
PHP 实现笛卡尔积
2019-05-27
Laravel中的$loop
2019-05-27
CentOS7 重置root密码
2019-05-27
Centos安装Python3
2019-05-27
PHP批量插入
2019-05-27
laravel连接sql server 2008
2019-05-27
Laravel 操作redis的各种数据类型
2019-05-27
Laravel框架学习笔记之任务调度(定时任务)
2019-05-27
laravel 定时任务秒级执行
2019-05-27
浅析 Laravel 官方文档推荐的 Nginx 配置
2019-05-27
Swagger在Laravel项目中的使用
2019-05-27
Laravel 的生命周期
2019-05-27
CentOS Docker 安装
2019-05-27
Nginx
2019-05-27
Navicat远程连接云主机数据库
2019-05-27
Nginx配置文件nginx.conf中文详解(总结)
2019-05-27