-
代理: 控制和管理访问
-
远程代理
(1) 在两个JVM中, 一个监视器想要远程调用另一个JVM上的对象, 那它先调用本地JVM的一个代理对象, 然后由代理对象处理所有网络通信的底层细节, 从而调用远程JVM上的对象
(2) headfirst.designpatterns.proxy.gumball中的使用RMI的示例没有测试通过
-
代理模式
为另一个对象提供一个替身或占位符, 以控制这个对象的访问
1° 远程代理控制访问远程对象
2° 虚拟代理控制访问创建开销大的资源
3° 保护代理控制访问资源的权限
-
虚拟代理
(1) 作为创建开销大的对象的代表, 直到真正需要一个对象的时候再创建这个对象. 在创建前和创建中时, 由虚拟代理来扮演对象的替身
(2) 示例: 网络加载显示图片, 加载成功前用"请等待"字样代替
class ImageProxy implements Icon { ... private volatile ImageIcon imageIcon; private final URL imageURL; private boolean retrieving = false; public void paintIcon(final 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; Thread retrievalThread = new Thread(new Runnable() { public void run() { try { setImageIcon(new ImageIcon(imageURL, "CD Cover")); c.repaint(); } catch (Exception e) { e.printStackTrace(); } } }); retrievalThread.start(); } } } ... }
-
代理模式和装饰器模式的区别
意图不同: 装饰者为对象增加行为, 代理控制对象的访问
另外, 装饰器可能包装很多层, 代理一般只包了一层
-
代理模式和适配器模式的区别
适配器模式会改变接口类型, 代理模式实现相同的接口
-
如何强制客户使用代理而不是使用真正的对象?
工厂方法
-
保护代理
(1) 保护代理的作用是控制权限, 由外面包的一层代理决定对内部对象的访问是否合法
(2) Java中利用反射支持动态的代理(所以叫动态代理), 在java.lang.reflect中
(3) 示例
PersonBean.java
public interface PersonBean { String getName(); String getGender(); ... void setName(String name); void setGender(String gender); ... void setHotOrNotRating(int rating); }
PersonBean是一个接口, 它提供了一系列的get/set方法, 但是PersonBean的实例对象有时需要加一层代理, 由代理来决定哪些方法可以被访问, 哪些不可以
TestProxy.java
public class TestProxy { ... public void drive() { PersonBean joe = getPersonFromDatabase("Joe Javabean"); PersonBean ownerProxy = getOwnerProxy(joe); ... } PersonBean getOwnerProxy(PersonBean person) { return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person)); } ... }
TestProxy是一个测试类, 在drive()方法中先创建了一个PersonBean对象joe, 但是joe的所有方法不应该全部被访问, 因此要得到joe的一个代理;
这里使用了java.lang.Proxy中的静态方法newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
Proxy就是PersonBean对象的代理, 但是当代理的方法被调用时, 内部其实会调用InvocationHandler对象的invoke()方法;
所以Proxy其实只是一个壳子, 重点要看InvocationHandler的实现类对象
OwnerInvocationHandler.java
public class OwnerInvocationHandler implements InvocationHandler { private PersonBean person; public OwnerInvocationHandler(PersonBean person) { this.person = person; } 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(); } return null; } }
OwnerInvocationHandler实现了InvocationHandler接口的invoke方法。 无论代理被调用的是什么方法, 最终一定会调用invoke();
Method是一个反射类, 可以获取到代理被调用的方法, 从而做出响应的选择
网友评论