代理模式
概述
某些情况下,一个客户不想或不能直接引用一个对象,此时可以通过代理对象实现间接引用,通过代理对象去掉客户不能看到的内容和添加客户需要的额外服务
模式实例
在一个论坛已注册用户和游客权限不同,已注册用户拥有发帖、修改注册信息、修改自己帖子等功能;而游客只能看到别人发的贴子,没有其他权限。本实例中我们使用代理模式中的保护代理,该代理用于控制对一个对象的访问,可以给不同用户提供不同级别的使用权限
AbstractPermission(抽象权限类)
public interface AbstractPermission {
public void modifyUserInfo();
public void viewNote();
public void publishNote();
public void modifyNote();
public void setLevel(int level);
}
RealPermission(真实权限类)
public class RealPermission implements AbstractPermission {
@Override
public void modifyUserInfo() {
System.out.println("修改用户信息");
}
@Override
public void viewNote() { }
@Override
public void publishNote() {
System.out.println("发布新帖");
}
@Override
public void modifyNote() {
System.out.println("修改发帖内容");
}
@Override
public void setLevel(int level) { }
}
PermissionProxy(权限代理类)
在 PermissionProxy 中定义了一个 RealPermission 对象,用于调用 RealPermission 中定义的真实业务方法,通过引入 PermissionProxy 类来对系统的使用权限进行控制
public class PermissionProxy implements AbstractPermission {
private RealPermission permission = new RealPermission();
private int level = 0;
@Override
public void modifyUserInfo() {
if (0 == level) {
System.out.println("对不起,你没有该权限");
} else if (1 == level) {
permission.modifyUserInfo();
}
}
@Override
public void viewNote() {
System.out.println("查看帖子");
}
@Override
public void publishNote() {
if (0 == level) {
System.out.println("对不起,你没有该权限");
} else if (1 == level) {
permission.publishNote();
}
}
@Override
public void modifyNote() {
if (0 == level) {
System.out.println("对不起,你没有该权限");
} else if (1 == level) {
permission.modifyNote();
}
}
@Override
public void setLevel(int level) {
this.level = level;
}
}
测试类 Client
public class Client {
public static void main(String[] args) {
AbstractPermission permission = new PermissionProxy();
permission.modifyUserInfo();
permission.viewNote();
permission.publishNote();
permission.modifyNote();
System.out.println("-------------------------");
permission.setLevel(1);
permission.modifyUserInfo();
permission.viewNote();
permission.publishNote();
permission.modifyNote();
}
}
静态代理
所谓静态代理,就是由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的 .class 文件就已经生成,上述的实例就属于静态代理
动态代理
Java 自带的基于接口的动态代理能在运行时根据 Java 代码中的指示动态生成的代理类,其实现相关类位于 java.lang.reflect 包,主要涉及两个类
InvocationHandler 接口:代理对象的关联调用接口,定义了 invoke 方法。当代理对象调用某个方法时,将被调度到关联调用接口的 invoke 方法处理
/**
* proxy 表示动态代理类
* method 表示需要代理的方法
* args 表示代理方法的参数数组
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
Proxy 类:该类提供了用于为接口创建代理实例的静态方法
public class Proxy implements java.io.Serializable {
...
/**
* 根据传入的接口类型返回一个动态创建的代理类实例
* loader 表示被代理类的类加载器
* interfaces 表示被代理类实现的接口列表(与真实主题类的接口列表一致)
* h 表示所指派的调用处理程序类
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
...
}
现有类 RealSubjectA ,通过 Java 动态代理实现一个代理类
抽象接口 AbstractSubject
public interface AbstractSubject {
public void request();
}
RealSubjectA
public class RealSubjectA implements AbstractSubject {
@Override
public void request() {
System.out.println("AAA");
}
}
动态代理类 DynamicProxy
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy() {}
public DynamicProxy(Object obj) {
this.obj = obj;
}
// 实现 invoke() 方法,调用在真实主题类中定义的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用之前");
// 利用反射调用方法,如果方法没有返回值则为 null
Object result = method.invoke(obj, args);
System.out.println("调用之后");
return result;
}
}
测试类 Client
public class Client {
public static void main(String[] args) {
AbstractSubject subject = new RealSubjectA();
InvocationHandler handler = new DynamicProxy(subject);
AbstractSubject subjectProxy = (AbstractSubject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
subject.getClass().getInterfaces(), handler);
subjectProxy.request();
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战