写在模式学习之前
什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式;每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案;当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式。
设计模式就是抽象出来的东西,它不是学出来的,是用出来的;或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以“模式专家”的角度来看,都是最佳的设计,不得不说是“最佳的模式实践”,这是因为你积累了很多的实践经验,知道“在什么场合代码应该怎么写”,这本身就是设计模式。
有人说:“水平没到,学也白学,水平到了,无师自通”。诚然,模式背熟,依然可能写不出好代码,更别说设计出好框架;OOP理解及实践经验到达一定水平,同时也意味着总结了很多好的设计经验,但"无师自通",却也未必尽然,或者可以说,恰恰是在水平和经验的基础上,到了该系统的学习一下“模式”的时候了,学习一下专家总结的结果,印证一下自己的不足,对于提高水平还是很有帮助的。
本系列的设计模式学习笔记,实际是对于《Java与模式》这本书的学习记录。
代理模式的定义
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
代理模式的英文叫做Proxy或Surrogate,中文都可译成“代理”。所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式和适配器模式的区别:适配器模式的用意是要改变所考虑的对象的接口,而代理模式并不能改变所代理对象的接口。
代理模式和装饰模式的区别:装饰模式应当为所装饰的对象提供增强功能,而代理模式对对象的使用施加控制,并不提供对象本身的增强功能。
代码模式和门面模式:有时候,门面模式兼任代理的职责,这时候,门面模式又叫做代理门面模式,或门面代理模式。
代理模式的结构
类图和时序图

vcfJq6O6tPrA7db3zOK9x8mrxNqyv7qs09C21NXmyrXW98zitcTS/dPDo6y007b4v8nS1NTayM66zsqxuvKy2df31ebKtdb3zOK21M/zo7u0+sDt1vfM4r3HyavM4bmp0ru49tPr1ebKtdb3zOK9x8mrz+DNrLXEvdO/2qOs0tSx47/J0tTU2sjOus7Ksbrytry/ydLUzOa0+tXmyrXW98zio6y/2NbGttTV5sq11vfM4rXE0v3Tw6OsuLrU8NTa0OjSqrXEyrG68rS0vajV5sq11vfM4rbUz/OjqLrNyb6z/dXmyrXW98zittTP86Opo7u0+sDtvcfJq82os6PU2r2rv827p7bLtffTw7Srtd24+NXmyrXW98zi1q7HsLvy1d/Wrrrzo6y2vNKq1rTQ0MSzuPay2df3o6y2+LK7yse1pbS/tdi9q7X308O0q7XduPjV5sq1ttTP86GjPGJyPgo8L3A+CjxwPqOoM6Op1ebKtdb3zOK9x8mro7q2qNLlwcu0+sDtvcfJq8v5tPqx7bXE1ebKtbbUz/Ohozxicj4KPC9wPgo8cD48YnI+CjwvcD4KPGgyPrT6wuvKtc/WPC9oMj4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">abstract class Subject { public abstract void request(); } class RealSubject extends Subject { public RealSubject() {} public void request() { System.out.println("From real subject"); } } class ProxySubject extends Subject { private RealSubject realSubject; public ProxySubject() {} public void request() { preRequest(); if(realSubject == null) { realSubject = new RealSubject(); } realSubject.request(); postRequest(); } //请求前的操作 private void preRequest() { //something you want to do before requesting } //请求后的操作 private void postRequest() { //something you want to do after requesting } }
JDK对代理模式的支持
自从JDK3之后,提供了反射类库,可以在运行期创建代理对象。下面的例子讲解java.lang.reflect.Proxy的使用方法。首先,这个例子为Vector对象提供一个代理对象,当Vector的任何方法被调用之前和调用之后,分别打印出两条信息,这表明代理对象有能力截获和控制这个Vector对象。
结构图

代码实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.util.*;
class VectorProxy implements InvocationHandler
{
private Object proxyobj;
public VectorProxy(Object obj)
{
this.proxyobj = obj;
}
public static Object factory(Object obj)
{
Class cls = obj.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(),
new VectorProxy(obj));
}
public Object invoke(Object proxy,Method method,Object[] args) throws Exception
{
System.out.println("before calling " + method);
if(args != null)
{
for(int i=0;i
代理的种类
如果按照使用目的来划分,代理有以下几种:远程(Remote)代理、虚拟(Virtual)代理、Copy-on-Write代理、保护(Protect or Access)代理、Cache代理、防火墙(Firewall)代理、同步化(Synchronization)代理、智能引用(Smart Reference)代理。
常用的有如下四种:
(1)远程代理:代理远程访问,优点是隐藏网络细节,可以像访问本地对象一