个人笔记,请不要被误导。
代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。(被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象,下面的三个例子远程代理、虚拟代理和保护代理分别代表这三类)。
实体和代理者实现同一个接口,用户用的时候不用关心究竟是谁,实现用户和实体的解耦。一般代理者都有实体的引用,这样才能调用它。这和适配器模式很相似区别在于前者代理者和实体实现同一个接口。
远程代理:
这里的例子是GumBallMonitor监视GumBallMachine(糖果机)的location、count和State(自己创建的类,表示糖果机状态)。这里用java RMI,它可以帮忙自动创建代理者。需要我们先建立一个远程接口
GumballMachineRemote implements Remote。然后建立远程实体类,它要实现GumballMachineRemote,而且要继承UnicastRemoteObject。这才为GumballMachineRemote接口和远程实体类建立联系,而且能为远程实体类建立代理者,GumballMachineRemote类型的代理者。此外,State类的对象不能被打包,只有序列化的数据类型才可以。所以State类声明时要加上extends Serializable。State类不需要通过网络传来的变量声明为transient。下面要做的就是通过Naming.rebind()方法把远程实体类对象的代理者注册,这里它有一个类似id的东西,以后可以通过Naming.lookUp()方法利用id传回相应远程实体对象的代理者。传回来的代理者类型是远程接口的,这是客户不用关心的。
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface GumballMachineRemote extends Remote {//考虑是否有风险,所有方法throw RemoteException
public int getCount() throws RemoteException;
public String getLocation() throws RemoteException;
public State getState() throws RemoteException;
}
import java.rmi.RemoteException;
public class GumballMonitor {
GumballMachineRemote gumballMachineRemote;
public GumballMonitor(GumballMachineRemote gumballMachineRemote){
this.gumballMachineRemote = gumballMachineRemote;
}
public void report(){
try {
gumballMachineRemote.getCount();
gumballMachineRemote.getLocation();
gumballMachineRemote.getState();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
虚拟代理:
这里例子是ImageProxy对象代理ImageIcon对象。因为后者创建的开销太大。加载一个很大的图片时不能一直空白,让用户等,要出现一个loading的图片,提示用户在加载。这个展示loading图片的对象,就是代理者——ImageProxy。ImageProxy判断ImageIcon是否加载完来执行相应操作。
public class ImageProxy implements Icon {
ImageIcon imageIcon;
DocFlavor.URL imageURL;
boolean retrieving = false;
Thread retrievalThread;
public ImageProxy(DocFlavor.URL url){
imageURL = url;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (imageIcon != null) imageIcon.paintIcon(c,g,x,y);
g.drawString("Loading",x + 300,y + 190);
if (!retrieving){
retrieving = true;
retrievalThread = new Thread(new Runnable() {
@Override
public void run() {
imageIcon = new ImageIcon(String.valueOf(imageURL),"CD Cover");
c.repaint();
}
});
retrievalThread.start();
}
}
@Override
public int getIconWidth() {
if (imageIcon == null) return 600;
else return imageIcon.getIconWidth();
}
@Override
public int getIconHeight() {
return 0;
}
}
保护代理:这是一个动态代理,代码执行之前Proxy类(注意是类!不是对象)还没被创建出来。
java.lang.reflect有自己的代理支持。这里的代理者会调用InvocationHandler类的方法,这里的方法判断客户发的需求,选择执行或不执行,达到保护的目的。
案例里有OwnerInvocationHandler和NonOwnerInvocationHandl两个InvocationHandler类,代理者根据发出请求的是自己还是别人(案例里自己不能改自己被点赞的次数,别人不能改自己的信息)调用这两个类,进行不同的操作。
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean personBean;
public OwnerInvocationHandler(PersonBean personBean){
this.personBean = personBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (method.getName().startsWith("get")) return method.invoke(personBean,args);
if (method.getName().equals("setHotOrNotRating")) throw new IllegalAccessException();
else if (method.getName().startsWith("set") ) return method.invoke(personBean,args);
}catch (InvocationTargetException e){
e.printStackTrace();
}
return null;
}
}
public interface PersonBean {
public String getName();
public void setName(String name);
public int getHotOrNotRating();
public void setHotOrNotRating(int hotOrNotRating);
}
import java.lang.reflect.Proxy;
public class PersonBeanImpl implements PersonBean {
String name;
int hotOrNotRating;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public int getHotOrNotRating() {
return hotOrNotRating;
}
@Override
public void setHotOrNotRating(int hotOrNotRating) {
this.hotOrNotRating = hotOrNotRating;
}
public PersonBean getOwnerProxy(){
return (PersonBean) Proxy.newProxyInstance(this.getClass().getClassLoader(),this.getClass().getInterfaces(),new OwnerInvocationHandler(this));
}
}
public void ProxyPattern_Protect(){
PersonBeanImpl personBean = new PersonBeanImpl();
PersonBean ownProxy = personBean.getOwnerProxy();
ownProxy.getHotOrNotRating();
ownProxy.setHotOrNotRating(100);
}