博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
结构型设计模式——代理设计模式
阅读量:3965 次
发布时间:2019-05-24

本文共 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()”方法的时候,其实调用的不是真正的方法,而是将方法名和参数传入到了InvocationHandlerinvoke()方法,进行代理增强
2、进行对象强转的时候,必须转为接口对象,而不能是实现对象,否则会抛出不能同级转换的异常
java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to com.flight.carryprice.rjmodel.impl.SomePolicy

转载地址:http://lpgzi.baihongyu.com/

你可能感兴趣的文章
mongoDB入门必读(概念与实战并重)
查看>>
通俗易懂解剖jbpm4
查看>>
rsync
查看>>
makefile
查看>>
linux 文件权限
查看>>
一些比较好的golang安全项目
查看>>
HTTP状态码
查看>>
go语言
查看>>
mysql mariaDB 以及存储引擎
查看>>
游戏行业了解介绍
查看>>
linux at 命令使用
查看>>
Go在windows下执行命令行指令
查看>>
inotify
查看>>
inode
查看>>
Shell: sh,bash,csh,tcsh等shell的区别
查看>>
golang ubuntu 配置 笔记
查看>>
vim 常用命令
查看>>
golang 开源项目
查看>>
ubntu 开发服务进程
查看>>
linux 常用命令以及技巧
查看>>