代理模式:控制和管理访问。
通过Internet为它们的代理对象搬运的整个方法调用而出名,它可以代替某些懒惰的对象做一些事情。
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
一定要:状态序列化
ImageProxy 加载图片
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;
public ImageProxy(URL url){
imageURL =url;
}
public int getIconHeight() {
if(imageIcon != null){
return imageIcon.getIconHeight();
}else{
return 800;
}
}
public int getIconWidth() {
if(imageIcon != null){
return imageIcon.getIconWidth();
}else{
return 600;
}
}
public void paintIcon(Component c, Graphics g, int x, int y) {
if(imageIcon != null){
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");
}catch(Exception e){
e.printStackTrace();
}
}
});
}
}
}
}
【1】代理模式有许多变体,都会对客户对主题施加的方法调用拦截下来。包括请求分发到远程主题,创建开销大的对象提供代表,提供某些级别的保护
【2】装饰者为对象增加行为,而代理是控制对象的访问;适配器会改变对象适配的接口,而代理则实现相同的接口
动态代理
【1】在运行时才将它的类创建出来,代码执行时,还没有proxy类,是根据需要从你传来的接口集创建的
【2】invocationHandler根本不是一个proxy,它只是一个帮助proxy的类,proxy会把调用转发给处理
proxy.new ProxyInstance()方法在运行时动态地创建的
【3】java5中的RMI何动态代理搭配使用,动态代理动态产生stub,远程对象的stub是java.lang.reflect.Proxy实例,它自动产生,处理所有把客户的本地的调用编程远程调用的细节
顾客不可以改变自己的HotOrNot评分,也不可以改变其他顾客的个人信息。
必须创建两个代理:一个访问自己的PersonBean对象,一个访问顾客的PersonBean对象。代理就可以控制在每一种情况下允许哪一种请求。
提供handler来处理代理转来转去的方法。
步骤一:创建InvocationHandler
写两个调用处理器,一个给拥有者使用,一个给非拥有者::当代理的方法被调用时,代理就会把这个调用转发给InvocationHandler
InvocationHandler只有一个名为invoke()的方法,不管代理被调用的是何种方法,处理器被调用的一定是invoke方法
A. 假设proxy的setHotOrNotRating()方法被调用。
proxy.setHotOrNotRating(9);
B. proxy会调用InvocationHandler的invoke()方法
invoke(Object proxy, Method method, Object[] args)
C. handler决定如何处置这个请求,可能会转发给RealSubject
return method.invoke(person, args);
继续创建
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//所有调用处理器都实现InvocationHandler
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean person;
//传入构造器,并保持它的引用
public OwnerInvocationHandler(PersonBean person){
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
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();
}
return null;
}
}
步骤二:创建proxy类并实例化Proxy对象
创建代理,将它的方法调用转发给OwnerInvocationhandler
//返回proxy对象的代理
Person getOwnerProxy(PersonBean person){
return (PersonBean) Proxy.newProxyInstance( //创建对象的代理
person.getClass().getClassLoader(), //将personBean的类载入器当做参数
person.getClass().getInterfaces(), //代理需要实现的接口
new OwnerInvocationHandler(person)); //调用处理器
}
测试配对服务
public class MatchMakingTestDrive {
public static void main(String[] args) {
MatchMakingTestDrive test = new MatchMakingTestDrive();
test.drive();
}
public MatchMakingTestDrive(){
initializeDatebae();
}
public void drive(){
//数据库中取出一个人
PersonBean joe = getPersonFromDatabase("Joe Javebean");
//创建一个拥有者代理
PersonBean ownerPorxy = getOwnerProxy(joe);
//调用getter
System.out.println("Name is " + ownerProxy.getName());
//调用setter
ownerProxy.setIntersts("bowling, Go");
try{
//行不通
ownerPorxy.setHotOtNotRating(10);
}catch(Exception e){
System.out.println("Can't set rating form owner proxy!");
}
System.out.println("Rating is " + ownerProxy.getHotOrNotRating());
//创建一个非拥有者代理
PersonBean nonOwnerPorxy = getOwnerProxy(joe);
System.out.println("Name is " + nonOwnerPorxy.getName());
nonOwnerPorxy.setIntersts("bowling, Go");
try{
nonOwnerPorxy.setHotOtNotRating(10);
}catch(Exception e){
System.out.println("Can't set rating form owner proxy!");
}
System.out.println("Rating is " + nonOwnerPorxy.getHotOrNotRating());
}
//..........其他方法,getOwnerProxy and getNonOwnerProxy
}
【应用】
防火墙代理:控制网络资源的访问,保护主题免于“坏客户”的侵害
缓存代理:为开销大的运算结果提供暂时存储:它也允许多个客户共享结果,以减少计算或网络延迟
智能引用代理:当主题被引用时,进行额外的动作
同步代理:在多线程的情况下为主题提供安全的访问
复杂隐藏代理:隐藏一个类的复杂集合的复杂度,并进行访问控制。外观代理
写入时复制代理:用来控制对象的复制,方法是延迟对象的复制,知道客户真的需要为止