一、引言
在实际开发过程中,我们常遇需要到为一个对象在不同的地址空间创建局部代理的情况,比如说一个Web服务器可能被不同的应用使用,我们就需要在每一个应用下都创建一个WEB服务器的局部引用。又或者在创建一些开销很大的对象实例时,就需要使用虚拟代理优化性能。比如打开网页时,网页中的图片总是先先出现图片框,然后在逐渐显示出图片,此时就是用虚拟代理替代了真实的图片,仅存储了图片的路径尺寸等信息。要想实现上功能,就要用到代理模式。
二、模式详解
1、模式分析
代理模式为其他对象提供一种代理以控制对这个对象的访问,它在客户与RealSubject之间设置了一个代理类,客户通过代理类访问RealSubject对象,说白了,就是在客户端中,调用RealSubject中方法的不是RealSubject自己类型的引用,而是通过一个代理类对象的引用调用。
如图-1所示,在代理模式中,Subject类定义了代理类和RealSubject类的功用方法接口,RealSubject类实现这些具体方法,而在代理类中则维护了一个RealSubject类型的引用,在实现的Subject接口方法中,代理类利用该引用调用RealSubject类的相应方法。而在客户端中,所有对RealSubject类性对象的操作哦都是通过地调用代理类的相关方法实现的,而不是直接对RealSubject类进行调用。
图-1 代理模式UML图
2、具体实现
我们用一个简单的例子来说明代理模式的具体实现过程。现有一个花心的坏男孩Tom打算同时追两个在不同学校里的女孩Lily和Lucy。追求的手段为送花、娃娃和巧克力,但是这两个女孩根本不认识Tom,而且Tom也很难同时到两个学校给女孩送东西,于是就找了分别在学校1和学校2里的朋友朋友1和朋友2替他去送。我们吧这个例子用Java实现后就是最基本的代理模式。
首先,我们我们对求爱行为进行了抽象,得到一个LoveAction接口,也就是UML中的抽象Subjiect类。
/**
* 该类为Subject类, Subject类是从RealSubject和代理类中抽象出来的,从而可以在任何使用
* RealSubject类的地方使用Proxy类。
*/
interface LoveAction {
public void giveDolls(String girlName);
public void giveFlower(String girlName);
public void giveChocolate(String girlName);
}/*LoveAction*/
接着,我们在定义追求者类实现求爱行为接口,并且定义代理者类Proxy类同样实现求爱行为接口,并且该类要维护一个追求者类的引用,在各个重写方法中,通过该引用关联追求者类对象的相应方法。
**
* 属于RealSubject类,该类的定义了一个追求者向梦中情人求爱的行动。
*/
class Persuitor implements LoveAction {
private String name = null;
public Persuitor(String name) {
this.name = name;
}// constructor
@Override
public void giveDolls(String girlName) {
System.out.println(name + " give " + girlName + " Dolls!");
}// giveDolls
@Override
public void giveFlower(String girlName) {
System.out.println(name + " give " + girlName + " flower!");
}// giveFlower
@Override
public void giveChocolate(String girlName) {
System.out.println(name + " give " + girlName + " Chocolate!");
}// giveChocolate
}/*Persuitor*/
/**
* Proxy就为代理类,拥有与RealSubject完全一样的共有方法,内部有一个对RealSubject类引用的私有
* 成员,在重写的方法中利用该成员实现对RealSubject类中相关方法的引用。
*/
class Proxy implements LoveAction {
private Persuitor persuitor = null;
public Proxy(Persuitor persuitor) {
this.persuitor = persuitor;
}// constructor
@Override
public void giveDolls(String girlName) {
persuitor.giveDolls(girlName);
}// giveDolls
@Override
public void giveFlower(String girlName) {
persuitor.giveFlower(girlName);
}// giveFlower
@Override
public void giveChocolate(String girlName) {
persuitor.giveChocolate(girlName);
}// giveChocolate
}/*Proxy*/
最后是客户端代码,在客户端中并没有直接调用追求者的各种求爱行为方法,而是通过代理,也就是Tom的两个朋友实现了Tom给两位女孩送东西的目的。
public class ProxytDemo {
/**
* 客户端代码,注意用户并没有直接操作Persuitor类,所有的操作均由Agent类对象实现。
* @param args
*/
public static void main(String[] args) {
Persuitor badBoy = new Persuitor("Tom");
// 通过朋友1向Lily求爱
System.out.println("In school 1: ");
Proxy friend1 = new Proxy(badBoy);
friend1.giveDolls("Lily");
friend1.giveFlower("Lily");
friend1.giveChocolate("Lily");
// 通过朋友2向Lucy求爱
System.out.println("In school 2: ");
Proxy friend2 = new Proxy(badBoy);
friend2.giveDolls("Lucy");
friend2.giveFlower("Lucy");
friend2.giveChocolate("Lucy");
}// main
}/*ProxytDemo*/
执行结果:
三、完整代码
package dp5_proxy_pattern;
/**
* 代理模式为其他对象提供一种代理以控制对这个对象的访问,它在客户与RealSubject之间设置了一个代
* 理类,客户通过代理类访问RealSubject对象,因此代理类中有余客户类完全相同的方法,为了完全一致
* 地实现客户类的功能,代理类中还要有一个客户类引用类型的私有成员。
*/
public class ProxytDemo {
/**
* 客户端代码,注意用户并没有直接操作Persuitor类,所有的操作均由Agent类对象实现。
* @param args
*/
public static void main(String[] args) {
Persuitor badBoy = new Persuitor("Tom");
// 通过朋友1向Lily求爱
System.out.println("In school 1: ");
Proxy friend1 = new Proxy(badBoy);
friend1.giveDolls("Lily");
friend1.giveFlower("Lily");
friend1.giveChocolate("Lily");
// 通过朋友2向Lucy求爱
System.out.println("In school 2: ");
Proxy friend2 = new Proxy(badBoy);
friend2.giveDolls("Lucy");
friend2.giveFlower("Lucy");
friend2.giveChocolate("Lucy");
}// main
}/*ProxytDemo*/
/**
* 该类为Subject类, Subject类是从RealSubject和代理类中抽象出来的,从而可以在任何使用
* RealSubject类的地方使用Proxy类。
*/
interface LoveAction {
public void giveDolls(String girlName);
public void giveFlower(String girlName);
public void giveChocolate(String girlName);
}/*LoveAction*/
/**
* 属于RealSubject类,该类的定义了一个追求者向梦中情人求爱的行动。
*/
class Persuitor implements LoveAction {
private String name = null;
public Persuitor(String name) {
this.name = name;
}// constructor
@Override
public void giveDolls(String girlName) {
System.out.println(name + " give " + girlName + " Dolls!");
}// giveDolls
@Override
public void giveFlower(String girlName) {
System.out.println(name + " give " + girlName + " flower!");
}// giveFlower
@Override
public void giveChocolate(String girlName) {
System.out.println(name + " give " + girlName + " Chocolate!");
}// giveChocolate
}/*Persuitor*/
/**
* Proxy就为代理类,拥有与RealSubject完全一样的共有方法,内部有一个对RealSubject类引用的私有
* 成员,在重写的方法中利用该成员实现对RealSubject类中相关方法的引用。
*/
class Proxy implements LoveAction {
private Persuitor persuitor = null;
public Proxy(Persuitor persuitor) {
this.persuitor = persuitor;
}// constructor
@Override
public void giveDolls(String girlName) {
persuitor.giveDolls(girlName);
}// giveDolls
@Override
public void giveFlower(String girlName) {
persuitor.giveFlower(girlName);
}// giveFlower
@Override
public void giveChocolate(String girlName) {
persuitor.giveChocolate(girlName);
}// giveChocolate
}/*Proxy*/