代理模式是一种结构型设计模式,用于在客户端和目标对象间创建一个代理对象,提供中介服务并可扩展功能。代理模式包括远程代理、虚拟代理、保护代理等类型,常用于权限控制、性能优化等场景。,,静态代理是指在编译时就已经确定了代理类和被代理类的关系,因此代理类与被代理类的实例化无关。动态代理是指在运行时动态生成代理类的实例,因此代理类与被代理类的实例化有关。
本文目录导读:
代理模式是一种结构型设计模式,它为其他对象提供了一种代理以控制对这个对象的访问,这种模式的主要目的是在不修改原始类的情况下,通过引入一个代理类来控制对原始类的访问,代理模式可以实现多种功能,如延迟加载、缓存、权限控制等,本文将详细介绍代理模式的概念、特点、应用场景以及实现方法,并通过实例进行讲解,帮助读者更好地理解和掌握代理模式。
代理模式的概念
代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对实际对象的访问,代理对象可以在访问实际对象之前或之后执行一些操作,从而实现对实际对象的功能扩展,代理模式主要分为静态代理和动态代理两种类型。
1、静态代理:在编译时就确定了代理类和被代理类的关系,代理类与被代理类通常具有相同的接口,静态代理的优点是性能开销小,缺点是灵活性较差。
2、动态代理:在运行时动态生成代理类,通常使用Java的反射机制来实现,动态代理的优点是灵活性高,可以根据需要选择不同的实现方式,缺点是性能开销较大。
代理模式的特点
1、封装:代理模式可以将内部实现细节隐藏起来,只暴露出有限的接口供外部调用,这样可以降低系统的耦合度,提高代码的可维护性。
2、代理关系:代理模式中存在一个代理对象和一个被代理对象,它们之间存在一种委托关系,代理对象负责处理来自客户端的请求,并将请求转发给被代理对象,被代理对象负责完成具体的业务逻辑。
3、可选性:代理模式可以选择是否使用代理对象来控制对实际对象的访问,这意味着在某些情况下,可以直接访问实际对象,而不需要通过代理对象。
代理模式的应用场景
1、延迟加载:当需要延迟获取某个对象时,可以使用代理模式,通过代理对象的加载操作,可以在真正需要该对象时才进行加载,从而节省系统资源。
2、缓存:当需要对某个频繁访问的对象进行缓存时,可以使用代理模式,通过代理对象的缓存操作,可以将结果存储起来,下次访问时直接返回缓存的结果,提高系统性能。
3、权限控制:当需要对某个对象的访问进行权限控制时,可以使用代理模式,通过代理对象的权限检查操作,可以实现对实际对象的访问控制。
代理模式的实现方法
1、静态代理:使用接口和实现类的方式实现静态代理,首先定义一个接口,然后创建一个实现该接口的静态代理类,在静态代理类中定义一个私有的被代理对象成员变量,通过构造函数传入实际对象,在实现接口的方法中,先判断是否使用了代理对象(即判断是否实现了接口),如果没有使用代理对象(即直接访问实际对象),则直接返回实际结果;如果使用了代理对象(即通过代理对象访问实际对象),则将请求转发给被代理对象并返回结果。
// 定义接口 public interface Subject { void request(); } // 实现接口的具体类 public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject request"); } } // 静态代理类 public class StaticProxy implements Subject { private RealSubject realSubject; public StaticProxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { if (realSubject != null) { // 没有使用代理对象(即直接访问实际对象) realSubject.request(); } else { // 使用了代理对象(即通过代理对象访问实际对象) System.out.println("StaticProxy request"); realSubject = new RealSubject(); // 将请求转发给被代理对象并返回结果(此处仅作示例,实际情况可能需要更复杂的逻辑) realSubject.request(); } } }
2、动态代理:使用Java的反射机制实现动态代理,首先定义一个接口和一个抽象类,然后创建一个实现该接口的具体类和一个抽象类,具体类负责实现业务逻辑,抽象类负责生成代理对象,在主程序中,通过反射机制创建具体类的对象和抽象类的实例,然后通过接口调用方法。
// 定义接口和抽象类 public interface Subject { void request(); } public abstract class AbstractProxy implements InvocationHandler { protected Object target; public AbstractProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before request"); // 在调用实际方法之前执行的操作(此处仅作示例,实际情况可能需要更复杂的逻辑) Object result = method.invoke(target, args); // 通过反射机制调用实际方法并返回结果(此处仅作示例,实际情况可能需要更复杂的逻辑) System.out.println("After request"); // 在调用实际方法之后执行的操作(此处仅作示例,实际情况可能需要更复杂的逻辑) return result; // 将结果返回给调用者(此处仅作示例,实际情况可能需要更复杂的逻辑) } } // 具体类和动态代理类(此处仅作示例,实际情况可能需要更复杂的逻辑) public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject request"); } } public class DynamicProxy implements InvocationHandlerAdapter<Subject> { // 实现InvocationHandlerAdapter接口是为了兼容JDK1.5之前的版本(此处仅作示例,实际情况可能需要更复杂的逻辑) private Object target; // 需要被动态代理的对象(此处仅作示例,实际情况可能需要更复杂的逻辑) /** * @param target 需要被动态代理的对象 */ * @throws IllegalArgumentException 如果传入的目标不是接口类型 */ * @throws InstantiationException 如果传入的目标无法实例化 */ * @throws IllegalAccessException 如果传入的目标的构造方法不可访问 */ public DynamicProxy(Object target) throws IllegalArgumentException, InstantiationException, IllegalAccessException{ this.target=target; Class<?> cls=target.getClass(); if(!cls.isInterface()) throw new IllegalArgumentException("Target object must be an interface type"); if((cls==null||cls==Object.class)&&!(target instanceof Subject)) throw new IllegalArgumentException("Target object must be an instance of Subject"); Field[] fields=getAllFields(cls); for(int i=0;i<fields.length;i++){ Field field=fields[i]; field.setAccessible(true); setFieldValue(field); setMethodValue(field); int mod=field.getModifiers(); if(Modifier.isStatic(mod)) continue; setMethodValue(getGetterMethod(field)); setMethodValue(getSetterMethod(field)); setMethodValue(getIsMethod(field)); setMethodValue(getHashCodeMethod()); setMethodValue(getToStringMethod()); setMethodValue(getEqualsMethod()); setMethodValue(getCloneMethod()); break; /*else continue;*//*if((Modifier.isFinal(mod))) continue;*//*if((Modifier.isAbstract(mod))) continue;*//*if((Modifier.isSynchronized(mod))) continue;*//*if((Modifier.isVolatile(mod))) continue;*//*if((Modifier.isTransient(mod))) continue;*//*if((Modifier.isPrivate(mod))) continue;*//*if((Modifier.isProtected(mod))) continue;*//*if((Modifier.isPublic(mod))) continue;*//*System.err.println("Field "+field+" is not accessible"); throw new IllegalStateException("Field "+field+" is not accessible");}} private static Field[] getAllFields(Class<?> cls){ return cls.getDeclaredFields();} private static void setFieldValue(Field field) throws IllegalAccessException{ field.setAccessible(true); field.set(null,new Object()); /*try{ field.setInt(null,42); field.setBoolean(null,true); field.setLong(null,9L); field.setDouble(null,3D); field.setFloat(null,3F); field.setCharSequence(null,"abc"); field.setByteBuffer(null,ByteBuffer.wrap("abc".getBytes())); field.setCharset(null,Charset.forName("GBK")); field.setCurrencyAmount(null,BigDecimal.valueOf("123456789")); field.setDate(null,new Date()); field.setLocale(null