【设计模式】代理模式-Proxy
转载:https://www.cnblogs.com/yangchongxing/p/7654725.html
代理模式定义如下:
Provide a surrogate or placeholder for another object to control access to it。为另一个对象提供一个代理或占位符以控制对它的访问。
代理模式使用非常广泛,理解代理模式对解决实际问题大有裨益的。使用代理模式必须让代理类和目标类实现相同的接口。
我们以添加用户业务为例
// 用户接口 package com.ycx.pattern.proxy; public interface UserService { public void insertUser(); } // 用户实现类 package com.ycx.pattern.proxy; public class UserServiceImpl implements UserService { @Override public void insertUser() { System.out.println("添加用户..."); } }
我们若要添加一个用户信息,需要new一个UserServiceImpl实例对象,然后调用insertUser方法。代码如下:
// 客户端 package com.ycx.pattern.proxy; public class Client { public static void main(String[] args) { UserService userServie = new UserServiceImpl(); userServie.insertUser(); } }
执行结果
添加用户...
静态代理
若这时新添一个业务,添加用户要在insertUser方法的开始和结束追加日志,其他地方没有这个业务,所以添加用户的业务不能修改,这种情况可以使用代理实现。代码如下:
// 代理 package com.ycx.pattern.proxy; public class UserServiceProxy implements UserService { private UserService _userService; public UserServiceProxy(UserService userService) { _userService = userService; } @Override public void insertUser() { // 开始日志 System.out.println("开始"); _userService.insertUser(); // 结束日志 System.out.println("结束"); } } // 客户端 package com.ycx.pattern.proxy; public class Client { public static void main(String[] args) { // 创建代理 UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl()); proxy.insertUser(); } }
执行结果
开始
添加用户...
结束
上边的代理是比较随便的,只要实现了用户接口,都可以,再看看使用指定代理,这样代理就必须是制定的。代码如下:
// 接口 package com.ycx.pattern.proxy; public interface UserService { public void insertUser(); public UserService getProxy(); } // 实现类 package com.ycx.pattern.proxy; public class UserServiceImpl implements UserService { private UserServiceProxy proxy = null; @Override public void insertUser() { // 关键代码是判断是不是自己指定的代理 if (!isProxy()) { System.out.println("请使用指定的代理"); } else { System.out.println("添加用户..."); } } // 关键代码判断代理 private boolean isProxy() { return this.proxy == null ? false : true; } // 关键代码返回自己的代理 @Override public UserService getProxy() { this.proxy = new UserServiceProxy(this); return this.proxy; } } // 代理 package com.ycx.pattern.proxy; public class UserServiceProxy implements UserService { private UserService _userService; public UserServiceProxy(UserService userService) { _userService = userService; } @Override public void insertUser() { System.out.println("开始"); _userService.insertUser(); System.out.println("结束"); } @Override public UserService getProxy() { return this; } } // 客户端 package com.ycx.pattern.proxy; public class Clicent { public static void main(String[] args) { // 只有使用自的代理才可以 UserService proxy = new UserServiceImpl().getProxy(); proxy.insertUser(); } }
执行结果
开始
添加用户...
结束
我们来直接new一个对象执行,或者new一个代理,验证结果。代码如下:
1 2 3 4 5 6 7 8 | // 客户端 package com.ycx.pattern.proxy; public class Client { public static void main(String[] args) { // 直接new一个对象 new UserServiceImpl().insertUser(); } } |
执行结果
请使用制定的代理
// 客户端 package com.ycx.pattern.proxy; public class Client { public static void main(String[] args) { // 直接new一个代理 UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl()); proxy.insertUser(); } }
执行结果
开始
请使用制定的代理
结束
从上面看都是不行的,只能使用指定的代理才可以。
下面是重头戏
动态代理-即面向横切面编程AOP(Aspect Oriented Programming)
InvocationHandler 是JDK提供的动态代理接口。Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
还是上面的例子,用动态代理实现代码如下:
// 动态代理 package com.ycx.pattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object object; MyInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始"); Object result = method.invoke(object, args); System.out.println("结束"); return result; } } // 客户端 package com.ycx.pattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { InvocationHandler h = new MyInvocationHandler(new UserServiceImpl()); // 使用Proxy获得实例 UserService proxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, h); proxy.insertUser(); } }
上面的实现方式客户端使用起来不方便,可以定义一个专门的客户代理。代码如下:
// 动态代理 package com.ycx.pattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object object; MyInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始"); Object result = method.invoke(object, args); System.out.println("结束"); return result; } } // 客户代理 package com.ycx.pattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxy { @SuppressWarnings("unchecked") public static <T> T newProxyInstance(T instance) { ClassLoader loader = instance.getClass().getClassLoader(); Class<?>[] interfaces = instance.getClass().getInterfaces(); InvocationHandler h = new MyInvocationHandler(instance); return (T) Proxy.newProxyInstance(loader, interfaces, h); } } // 客户端 package com.ycx.pattern.proxy; public class Client { public static void main(String[] args) { // 使用定制的代理返回实例 UserService proxy = DynamicProxy.newProxyInstance(new UserServiceImpl()); proxy.insertUser(); } }
待续...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南