在代理模式Proxy Pattern中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
意图:为其他对象提供一种代理,以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因
(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,
我们可以在访问此对象时加上一个对此对象的访问层。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。 缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景:按职责来划分,通常有以下使用场景: 远程代理。Cache代理。防火墙(Firewall)代理。
注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。 |
代理模式可以分为2种:静态代理模式和动态代理模式
静态模式:
1、抽象角色--接口 public interface Image { void display(); } 2、具体的目标对象---被代理的对象 public class RealImage implements Image { @Override public void display() { System.out.println("Displaying real image "); } } 3、代理对象,由于只能调用display方法,所以代理类也需要实现接口 public class ProxyImage implements Image{ private Image obj; --被代理的对象 public ProxyImage(Image target){ this.obj = target; } public void display() { System.out.println("前置处理,可以决定是否需要调用目标对象的方法"); obj.display(); } } 4、测试调用 Image target=new RealImage();//创建目标对象,也就是被代理对象 Image proxy=new ProxyImage(target);//创建代理对象,同时注入被代理对象 proxy.display();从形式上看似乎调用的是代理对象的方法,但是事实上具体处理的逻辑是被代理对象中的处理
|
缺点: 需要目标接口,而且针对一个接口需要一个代理对象,可能会导致类爆炸问题 |
动态代理机制:
有2种实现方式:
使用JDK的动态代理:要求必须有对应的接口
使用 CGLib的动态代理:可以没有对应的接口。
使用Cglib创建代理的效率略低于JDK动态代理
JDK反射包中的相关接口和工厂类
接口java.lang.reflect.InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable; }
• proxy - 在其上调用方法的代理实例
• method - 对应于在代理实例上调用的接口方法的 Method 实例
• args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null
1、抽象角色 public interface Image { void display(); }
2、具体的目标对象---被代理的对象 public class RealImage implements Image { @Override public void display() { System.out.println("Displaying real image "); } }
3、定义代理回调,不是代理对象类,没有具体的代理对象类定义 public class MyProxyHandler implements InvocationHandler { private Object target;
public MyProxyHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 不管未来调用的是代理类的任何方法,实际上都是执行这个回调 System.out.println("签订演艺合同"); // 限制对目标对象的访问 Object res = method.invoke(target, args); System.out.println("收钱~~~"); return res; }
} 4、测试调用 Image proxy = (Image) Proxy.newProxyInstance(Image.class.getClassLoader(),new Class[]{Image.class }, new MyProxyHandler(new RealImage()));创建代理对象,注意这个代理对象是由工具类动态生成的,没有对应的代理类定义 proxy.display();
|
Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)生成代理类
– loader - 定义代理类的类加载器
– interfaces - 代理类要实现的接口列表
– h - 指派方法调用的调用处理程序