代理模式是一种结构型设计模式,用于在客户端和目标对象间创建一个代理对象,提供中介服务并可扩展功能。代理模式包括远程代理、虚拟代理、保护代理等类型,常用于权限控制、性能优化等场景。,,代理模式包含抽象主题、代理主题和真实主题三个角色,代理类持有真实主题的引用,可在调用真实方法前后添加额外操作。
本文目录导读:
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问,这种模式主要分为静态代理和动态代理,静态代理是在编译时就确定代理类和被代理类的关系,而动态代理是在运行时动态生成代理类,本文将详细介绍代理模式的概念、特点、应用场景以及实现方法,并通过实际案例进行演示。
代理模式的概念
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问,这种模式主要分为静态代理和动态代理,静态代理是在编译时就确定代理类和被代理类的关系,而动态代理是在运行时动态生成代理类,本文将详细介绍代理模式的概念、特点、应用场景以及实现方法,并通过实际案例进行演示。
代理模式的特点
1、代理模式可以实现对原对象的封装,隐藏原对象的实现细节,对外提供统一的接口。
2、代理模式可以在不修改原对象的基础上,动态地为其添加新的功能,如日志记录、权限控制等。
3、代理模式可以实现对原对象的装饰,即在不改变原有对象的基础上,为其添加新的功能或者改变其行为。
4、代理模式可以帮助我们更好地处理系统中的横切关注点,将这些关注点与业务逻辑分离,提高系统的可维护性和可扩展性。
代理模式的应用场景
1、远程代理:在分布式系统中,可以通过代理来实现对远程对象的访问,如RMI、RPC等。
2、安全控制:通过代理来实现对系统资源的安全控制,如权限控制、日志记录等。
3、性能监控:通过代理来实时监控系统的状态,如CPU使用率、内存占用等。
4、事务管理:通过代理来管理事务的提交和回滚,确保数据的一致性。
5、缓存机制:通过代理来实现对缓存数据的管理和更新,提高系统的响应速度。
代理模式的实现方法
1、静态代理:在编译时就确定了代理类和被代理类的关系,通常使用接口作为被代理类和代理类之间的桥梁,以下是一个简单的静态代理示例:
// 定义一个接口 public interface Subject { void request(); } // 实现接口的具体类 public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject: Handling request."); } } // 代理类,实现接口并持有被代理对象的引用 public class Proxy implements Subject { private RealSubject realSubject; @Override public void request() { if (realSubject == null) { realSubject = new RealSubject(); } preRequest(); realSubject.request(); postRequest(); } // 在调用前执行的操作 private void preRequest() { System.out.println("Proxy: Pre-processing before request."); } // 在调用后执行的操作 private void postRequest() { System.out.println("Proxy: Post-processing after request."); } }
2、动态代理:在运行时动态生成代理类,通常使用Java的反射机制来实现,以下是一个简单的动态代理示例:
// 定义一个接口 public interface Subject { void request(); } // 实现接口的具体类 public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject: Handling request."); } } // 实现InvocationHandler接口的动态代理类 public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("request")) { System.out.println("DynamicProxy: Pre-processing before request."); } else if (method.getName().equals("toString")) { return "DynamicProxy for target: " + target; } else if (method.getName().equals("hashCode")) { return System.identityHashCode(target); } else if (method.getName().equals("equals")) { Class<?>[] interfaces = target.getClass().getInterfaces(); for (Class<?> anInterface : interfaces) { if (anInterface == method.getDeclaringClass()) continue; // skip itself and Object.class!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!::1906475289006640256::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::0::1906475289006640256::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1919378887438999525::1/2/3/4/5/6/7/8/9/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w" || method.getDeclaringClass().isAssignableFrom(anInterface)) return true; // skip non-interface methods on interfaces and Object class itself to avoid infinite loop when calling equals method on same instance from two different classes with the same name but different signatures (e.g. compareTo in String and Integer) or vice versa (e.g. hashCode in String and Object). // If you don't want to skip these methods, you can useinstanceof
operator instead ofisAssignableFrom
. // But be careful about usinginstanceof
, because it will also consider subclasses of the target class as its subtypes // (e.g.List<String>
is a subclass ofCollection<String>
). // So we need to check bothmethod.getDeclaringClass()
andanInterface
here to make sure that we don't callequals
orhashCode
on those methods by mistake when they are not overridden in the target class or its subclasses (e.g.List<String>
has neitherequals
norhashCode
method overridden). // Note that some frameworks like Apache Commons Lang provide more convenient way to handle this issue by usingDefaultMethodUtils
class to detect and register default methods automatically for you when you use their reflection utilities likeReflectionUtils
, so you don't need to worry about this problem at all unless you want to customize your own implementation of dynamic proxies or use other reflection utilities provided by other libraries besides Commons Lang. // Finally, we can useinvokeSpecial
method to call the corresponding method in the target object without invoking its superclass implementation first (which is usually used for constructors), or we can useinvokeInterface
method to call the corresponding method in the target object through the proxy interface (which is usually used for non-static methods), or we can useinvoke
method directly to call the corresponding method in the target object through the proxy interface (which is