终于……看到了……代理模式……
我觉得……
这个模式……
真的……
好难啊……
首先是远程代理
↑都是这个东西好难
使用代理模式创建代表(representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象,创建开销大的对象或者需要安全控制的对象
类图:
RealSubject是真正做事的对象,它是被Proxy代理和控制访问的对象。客户与RealSubject的交互都必须通过Proxy。
远程代理:
虚拟代理:
栗子:
写一个程序展示CD封面,当封面没有加载好的时候,就显示“加载中。。。”
创建一个代理类,当照片没有加载好的时候,就显示加载中,但加载好之后,就好所有方法委托给真正的照片类。
为什么要虚拟代理呢?因为没加载好的时候,还没有图片,这个代理就是一个虚拟的图片,,,
<span style="color: #0000ff;">import<span style="color: #000000;"> javax.swing.ImageIcon; <span style="color: #008000;">//<span style="color: #008000;"> 代理Icon也要实现Icon接口
<span style="color: #0000ff;">public <span style="color: #0000ff;">class ImageProxy <span style="color: #0000ff;">implements<span style="color: #000000;"> Icon {
ImageIcon imageIcon;
URL imageURL;
Thread retrievalThread;
<span style="color: #0000ff;">boolean retrieving = <span style="color: #0000ff;">false<span style="color: #000000;">;
</span><span style="color: #008000;">//</span><span style="color: #008000;"> URL是图片资源位置</span>
<span style="color: #0000ff;">public</span><span style="color: #000000;"> ImageProxy(URL url) {
imageURL </span>=<span style="color: #000000;"> url;
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 在图像加载完毕前 返回默认的宽和高</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getIconWidth() {
</span><span style="color: #0000ff;">if</span> (imageIcon != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> imageIcon.getIconWidth();
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
</span><span style="color: #0000ff;">return</span> 800<span style="color: #000000;">;
}
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getIconHeight() {
</span><span style="color: #0000ff;">if</span> (imageIcon != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> imageIcon.getIconHeight();
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
</span><span style="color: #0000ff;">return</span> 600<span style="color: #000000;">;
}
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> paintIcon(<span style="color: #0000ff;">final</span> Component c,Graphics g,<span style="color: #0000ff;">int</span> x,<span style="color: #0000ff;">int</span><span style="color: #000000;"> y) {
</span><span style="color: #0000ff;">if</span> (imageIcon != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 如果已经有Icon 就告诉它画出自己</span>
<span style="color: #000000;"> imageIcon.paintIcon(c,g,x,y);
} <span style="color: #0000ff;">else<span style="color: #000000;"> {
<span style="color: #008000;">//<span style="color: #008000;"> 否则就显示加载中
g.drawString("Loading CD cover,please wait...",x+300,y+190<span style="color: #000000;">);
<span style="color: #0000ff;">if (!<span style="color: #000000;">retrieving) {
<span style="color: #008000;">//<span style="color: #008000;"> 如果我们还有试着取出图像 那么就开始取图像
retrieving = <span style="color: #0000ff;">true<span style="color: #000000;">;
retrievalThread = <span style="color: #0000ff;">new Thread(<span style="color: #0000ff;">new<span style="color: #000000;"> Runnable() {
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> run() {
<span style="color: #0000ff;">try<span style="color: #000000;"> {
<span style="color: #008000;">//<span style="color: #008000;"> 要在这里加载真正的Icon图像
<span style="color: #008000;">//<span style="color: #008000;"> 请注意 加载图像和ImageIcon是同步的 也就是说 只有在加载完成之后 ImageIcon构造器才会返回
<span style="color: #008000;">//<span style="color: #008000;"> 这样 我们的程序就会耗在这里 动弹不得 也没办法显示消息
<span style="color: #008000;">//<span style="color: #008000;"> 我们不希望挂起整个用户界面 所以用另一个线程取出图像
<span style="color: #008000;">//<span style="color: #008000;"> 在线程中 我们实例化此Icon对象 其构造器会在图像加载完成后才返回
<span style="color: #008000;">//<span style="color: #008000;"> 当图像准备好时 我们告诉Swing要重绘
imageIcon = <span style="color: #0000ff;">new ImageIcon(imageURL,"CD cover"<span style="color: #000000;">);
c.repaint();
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (Exception e) {
e.printStackTrace();
}
}
});
retrievalThread.start();
}
}
}
}
然后是显示图片的ImageComponent类
<span style="color: #0000ff;">private<span style="color: #000000;"> Icon icon;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ImageComponent(Icon icon) {
</span><span style="color: #0000ff;">this</span>.icon =<span style="color: #000000;"> icon;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setIcon(Icon icon) {
</span><span style="color: #0000ff;">this</span>.icon =<span style="color: #000000;"> icon;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> paintComponent(Graphics g) {
</span><span style="color: #0000ff;">super</span><span style="color: #000000;">.paintComponent(g);
</span><span style="color: #0000ff;">int</span> w =<span style="color: #000000;"> icon.getIconWidth();
</span><span style="color: #0000ff;">int</span> h =<span style="color: #000000;"> icon.getIconHeight();
</span><span style="color: #0000ff;">int</span> x = (800 - w)/2<span style="color: #000000;">;
</span><span style="color: #0000ff;">int</span> y = (600 - h)/2<span style="color: #000000;">;
icon.paintIcon(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,y);
}
}
测试类:
ImageComponent imageComponent;
JFrame frame </span>= <span style="color: #0000ff;">new</span> JFrame("CD封面加载器"<span style="color: #000000;">);
JMenuBar menuBar; </span><span style="color: #008000;">//</span><span style="color: #008000;"> 菜单栏 </span>
JMenu menu; <span style="color: #008000;">//</span><span style="color: #008000;"> 菜单 </span>
Map<String,String> cds = <span style="color: #0000ff;">new</span> HashMap<><span style="color: #000000;">();
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> main (String[] args) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> ImageProxyTestDrive();
}
</span><span style="color: #0000ff;">public</span> ImageProxyTestDrive() <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 构造菜单项用的, key=CD名,value=URL </span>
cds.put("轨迹","http://images.cnblogs.com/cnblogs_com/wenruo/873448/o_%E8%BD%A8%E8%BF%B9.png"<span style="color: #000000;">);
cds.put(</span>"分我一半的眼泪","http://images.cnblogs.com/cnblogs_com/wenruo/873448/o_%E5%88%86%E6%88%91%E4%B8%80%E5%8D%8A%E7%9A%84%E7%9C%BC%E6%B3%AA.jpg"<span style="color: #000000;">);
cds.put(</span>"光荣","http://images.cnblogs.com/cnblogs_com/wenruo/873448/o_%E5%85%89%E8%8D%A3.png"<span style="color: #000000;">);
cds.put(</span>"画中仙","http://images.cnblogs.com/cnblogs_com/wenruo/873448/o_%E7%94%BB%E4%B8%AD%E4%BB%99.jpg"<span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 设置初始的CD封面 </span>
URL initialURL = <span style="color: #0000ff;">new</span> URL(cds.get("轨迹"<span style="color: #000000;">));
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 建立菜单栏 </span>
menuBar = <span style="color: #0000ff;">new</span><span style="color: #000000;"> JMenuBar();
menu </span>= <span style="color: #0000ff;">new</span> JMenu("Favorite CDs"<span style="color: #000000;">);
menuBar.add(menu);
frame.setJMenuBar(menuBar);
</span><span style="color: #0000ff;">for</span>(Entry<String,String><span style="color: #000000;"> e : cds.entrySet()) {
String name </span>=<span style="color: #000000;"> e.getKey();
String url </span>=<span style="color: #000000;"> e.getValue();
JMenuItem menuItem </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> JMenuItem(name);
menu.add(menuItem);
menuItem.addActionListener(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> ActionListener() {
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> actionPerformed(ActionEvent event) {
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
imageComponent.setIcon(</span><span style="color: #0000ff;">new</span> ImageProxy(<span style="color: #0000ff;">new</span><span style="color: #000000;"> URL(url)));
} </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (MalformedURLException e) {
e.printStackTrace();
}
frame.repaint();
}
});
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> set up frame and menus </span>
Icon icon = <span style="color: #0000ff;">new</span><span style="color: #000000;"> ImageProxy(initialURL);
imageComponent </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ImageComponent(icon);
frame.getContentPane().add(imageComponent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(</span>800,600<span style="color: #000000;">);
frame.setVisible(</span><span style="color: #0000ff;">true</span><span style="color: #000000;">);
}
}
一个虚拟代理就完成了。。。
加载前:
在上面的例子中,每一次都是创建新的ImageProxy来取得对象,即使图像已经被取出来过,可以把已加载的图片放入缓存中,这就是缓存代理。
缓存代理(Caching Proxy)会维护之前创建的对象,当收到请求时,在可能的情况下返回缓存对象。
动态代理:Java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。因为实际的代理类是在运行时被创建的,我们称这个技术为:动态代理。
动态代理类图:
动态代理的实现
有一个系统,存有每个人的信息,和每个人的评分。现在希望每个人不能给自己评分,而更改个人信息只有自己能做到。
于是设计两个代理,一个控制访问自己的类,一个控制访问其他人。
首先是个人信息的接口:
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setName(String name);
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setGender(String gender);
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setInterests(String interests);
</span><span style="color: #0000ff;">void</span> setHotOrNotRating(<span style="color: #0000ff;">int</span><span style="color: #000000;"> rating);
}
具体实现类
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getHotOrNotRating() {
</span><span style="color: #0000ff;">if</span> (ratingCount == 0) <span style="color: #0000ff;">return</span> 0<span style="color: #000000;">;
</span><span style="color: #0000ff;">return</span> (rating /<span style="color: #000000;"> ratingCount);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setName(String name) {
</span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setGender(String gender) {
</span><span style="color: #0000ff;">this</span>.gender =<span style="color: #000000;"> gender;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setInterests(String interests) {
</span><span style="color: #0000ff;">this</span>.interests =<span style="color: #000000;"> interests;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setHotOrNotRating(<span style="color: #0000ff;">int</span><span style="color: #000000;"> rating) {
</span><span style="color: #0000ff;">this</span>.rating +=<span style="color: #000000;"> rating;
ratingCount</span>++<span style="color: #000000;">;
}
}
创建两个InvocationHandler,一个给拥有者使用
PersonBean person;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> OwnerInvocationHandler(PersonBean person) {
</span><span style="color: #0000ff;">this</span>.person =<span style="color: #000000;"> person;
}
@Override
</span><span style="color: #0000ff;">public</span> Object invoke(Object proxy,Method method,Object[] args) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Throwable {
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
</span><span style="color: #0000ff;">if</span> (method.getName().startsWith("get"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> method.invoke(person,args);
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (method.getName().equals("setHotOrNotRating"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalAccessException();
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (method.getName().startsWith("set"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> method.invoke(person,args);
}
} </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InvocationTargetException e) {
e.printStackTrace();
}
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}
}
一个给非拥有者使用
PersonBean person;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> NotOwnerInvocationHandler(PersonBean person) {
</span><span style="color: #0000ff;">this</span>.person =<span style="color: #000000;"> person;
}
@Override
</span><span style="color: #0000ff;">public</span> Object invoke(Object proxy,Object[] args) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> IllegalAccessException {
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
</span><span style="color: #0000ff;">if</span> (method.getName().startsWith("get"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> method.invoke(person,args);
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (method.getName().equals("setHotOrNotRating"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> method.invoke(person,args);
} </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (method.getName().startsWith("set"<span style="color: #000000;">)) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalAccessException();
}
} </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InvocationTargetException e) {
e.printStackTrace();
}
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}
}
测试类:
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
MatchMakingTestDrive test = <span style="color: #0000ff;">new<span style="color: #000000;"> MatchMakingTestDrive();
test.drive();
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> MatchMakingTestDrive() {
initializeDatabsae();
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> drive() {
PersonBean joe </span>= getPersonFromDatabase("Joe JavaBean"<span style="color: #000000;">);
PersonBean ownerProxy </span>=<span style="color: #000000;"> getOwnerProxy(joe);
System.out.println(</span>"Name is " +<span style="color: #000000;"> ownerProxy.getName());
ownerProxy.setInterests(</span>"bowling,Go"<span style="color: #000000;">);
System.out.println(</span>"Interests set from owner proxy"<span style="color: #000000;">);
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
ownerProxy.setHotOrNotRating(</span>10);<span style="color: #008000;">//</span><span style="color: #008000;">不能给自己平分</span>
} <span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
System.out.println(</span>"Can't set rating from owner proxy"<span style="color: #000000;">);
}
System.out.println(</span>"Rating is " +<span style="color: #000000;"> ownerProxy.getHotOrNotRating());
PersonBean nonOwnerProxy </span>=<span style="color: #000000;"> getNonOwnerProxy(joe);
System.out.println(</span>"Name is " +<span style="color: #000000;"> nonOwnerProxy.getName());
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
nonOwnerProxy.setInterests(</span>"bowling,Go"<span style="color: #000000;">);
} </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
System.out.println(</span>"Can't set interests from non owner proxy"<span style="color: #000000;">);
}
nonOwnerProxy.setHotOrNotRating(</span>3<span style="color: #000000;">);
System.out.println(</span>"Rating set from non owner proxy"<span style="color: #000000;">);
System.out.println(</span>"Rating is " +<span style="color: #000000;"> nonOwnerProxy.getHotOrNotRating());
}
PersonBean getOwnerProxy(PersonBean person) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (PersonBean) Proxy.newProxyInstance(
person.getClass().getClassLoader(),person.getClass().getInterfaces(),</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> OwnerInvocationHandler(person));
}
PersonBean getNonOwnerProxy(PersonBean person) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (PersonBean) Proxy.newProxyInstance(
person.getClass().getClassLoader(),</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> NotOwnerInvocationHandler(person));
}
</span><span style="color: #008000;">/**</span><span style="color: #008000;">**********假装这是数据库实现*************</span><span style="color: #008000;">*/</span><span style="color: #000000;">
ArrayList</span><PersonBean><span style="color: #000000;"> beans;
</span><span style="color: #0000ff;">void</span><span style="color: #000000;"> initializeDatabsae() {
beans </span>= <span style="color: #0000ff;">new</span> ArrayList<><span style="color: #000000;">();
beans.add(</span><span style="color: #0000ff;">new</span> PersonBeanImpl("Joe JavaBean","男","学习"<span style="color: #000000;">));
}
PersonBean getPersonFromDatabase(String name) {
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < beans.size(); ++<span style="color: #000000;">i) {
PersonBean person </span>=<span style="color: #000000;"> beans.get(i);
</span><span style="color: #0000ff;">if</span> (person.getName().equals(name)) <span style="color: #0000ff;">return</span><span style="color: #000000;"> person;
}
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}
}
一些其他的代理模式:
防火墙代理:控制网络资源的访问,保护主题免于“坏客户”的侵害。
智能引用代理:当主题被引用时,进行额外的动作,例如计算一个对象呗引用的次数。
缓存代理:为开销大的运算结果提供暂时的存储,它也允许多个客户共享结果,以减少计算或网络延迟。
同步代理:在多线程的情况下为主题提供安全的访问。
复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度,并进行访问控制。
写入时复制代理:用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。这是虚拟代理的变体。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。