代理模式的定义
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。使用代理模式创建代表(representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。代理模式主要涉及到三类角色:1)代理角色(Proxy)2)抽象主题角色(Subject) 3)真实主题角色(Real Subject)
代理角色:保存一个引用使得代理可以访问实体。因为若RealSubject和Subject的接口相同,Proxy会引用Subject,这样代理就可以用来替代实体。还可以控制对实体的存取,并可能负责创建和删除它。还有其他的功能比如:远程代理负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求;虚拟代理作为创建开销大的对象的代表,可以将对象延迟到真正需要它的时候才创建;保护代理检查调用者是否具有实现一个请求所必需的访问权限。
抽象主题角色:定义真实主题角色和抽象主题角色Proxy共同的接口,这样就可以使任何使用真实主题角色的时候都可以使用代理(抽象主题角色)
真实主题角色:定义了代理角色所代表的具体对象。
几种代理模式的java实现
远程代理的java实现可以参考Java RMI 在Eclipse中的实现。
本文主要对虚拟代理(Virtual Proxy)和保护代理(Protection Proxy)进行了分析和实现。
虚拟代理作为创建开销大的对象的代表,经常直到我们正在需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理会将请求直接委托给对象。代码片段如下所示:
ImageProxy代理,它们实现共同的接口Icon,当ImageIcon为null时,imageProxy会显示自身的内容,当ImageIcon为非空时,会委托imageIcon显示它的内容
import java.awt.Component;
import java.awt.Graphics;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.ImageIcon;
public class ImageProxy implements Icon {
ImageIcon imageIcon;
URL imageURL;
Thread retrievalThread;
boolean retrieving=false;
//我们将图像的url传入到构造器中。这是我们希望显示的图像所在的位置
public ImageProxy(URL url){
imageURL=url;
}
//在图像加载完毕前,返回默认的宽和高。图像加载完毕后,转给imageIcon处理
public int getIconWidth(){
if(imageIcon!=null){
return imageIcon.getIconWidth();
}else
return 800;
}
public int getIconHeight(){
if(imageIcon!=null){
return imageIcon.getIconHeight();
}else
return 600;
}
//当需要在屏幕上绘制图像时,就调用此方法
public void paintIcon(final Component c,Graphics g,int x,int y){
if(imageIcon!=null){
//如果你已经有icon,就告诉它画出自己
imageIcon.paintIcon(c, g, x, y);
}else{
//否则就显示这个“加载中”的消息
g.drawString("Loading CD cover,please wait...",x+300,y+190);
if(!retrieving){
retrieving=true;
retrievalThread=new Thread(new Runnable(){
public void run(){
try{
imageIcon=new ImageIcon(imageURL,"CD Cover");
c.repaint();
}catch(Exception e){
e.printStackTrace();
}
}
});
retrievalThread.start();
}
}
}
}
在讲保护代理之前,我们需要先了解下动态代理。Java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。因为实际的类是在运行时创建的,我们称这个技术为动态代理。这边我们使用InvocationHandler来实现代理的行为,java负责创建真实代理类对象。我们只需提供在方法调用发生时知道做什么的handler。代码片段如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//所有调用处理器都实现InvocationHandler接口
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public OwnerInvocationHandler(PersonBean person){
this.person=person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {
try{
if(method.getName().startsWith("get")){
return method.invoke(person, args);
}else if(method.getName().equals("setHotOrNotRating")){
throw new IllegalAccessException();
}else if(method.getName().startsWith("set")){
return method.invoke(person, args);
}
//如果真正主题抛出异常的话,就会执行这里
}catch(InvocationTargetException e){
e.printStackTrace();
}
// TODO Auto-generated method stub
return null;
}
}