1.模式动机与定义
代理模式定义:为其他对象提供一种代理以控制对象的访问。
2.模式结构与分析
/**
* 定义了RealSubject和Proxy的共同接口,使得在任何使用RealSubject的地方都可以使用Proxy
*/
public interface Subject {
void request();
}
/**
* 定义了Proxy所代表的真正实体
*/
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject invoke request() method");
}
}
/**
* 持有真实实体RealSubject的引用,使得Proxy可以访问真实实体
* 并实现了Subject接口,这样代理就可以代替真实实体
*/
public class Proxy implements Subject{
private RealSubject subject;
public Proxy() {
this.subject = new RealSubject();
}
@Override
public void request() {
this.subject.request();
}
}
public class Client {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.request();
}
}
RealSubject invoke request() method
3.模式实例与解析
模式实例:
学校里男同学A想要女同学B做自己的女朋友,想送女同学B礼物来追求女同学B,但是自己不好意思直接送,于是委托中间人来帮自己送礼物。
/**
* 校园中的漂亮女同学
*/
public class SchoolGirl {
private String name;
public SchoolGirl(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
GiveGift接口对应于代理模式类图中的Subject。
public interface GiveGift {
void giveDolls();
void giveFlowers();
void giveChocolate();
}
下面的Pursuer对应于类图中的RealSubject,是真实实体对象。
/**
* 女同学的追求者
*/
public class Pursuer implements GiveGift {
private SchoolGirl girl;
public Pursuer(SchoolGirl girl) {
this.girl = girl;
}
@Override
public void giveDolls() {
System.out.println("[追求者]送给[" + this.girl.getName() + "]洋娃娃");
}
@Override
public void giveFlowers() {
System.out.println("[追求者]送给[" + this.girl.getName() + "]鲜花");
}
@Override
public void giveChocolate() {
System.out.println("[追求者]送给[" + this.girl.getName() + "]巧克力");
}
}
Proxy对应于类图中的Proxy,为代理对象,其实现了与真实实体对象相同的接口GiveGift,并持有真实实体Pursuer实例的引用。
/**
* 女同学的追求者不好意思直接给女同学送礼物
* 于是,追求者委托Proxy这个中间人来给女同学送礼物
*/
public class Proxy implements GiveGift {
private Pursuer pursuer;
public Proxy(SchoolGirl girl) {
this.pursuer = new Pursuer(girl);
}
@Override
public void giveDolls() {
this.pursuer.giveDolls();
}
@Override
public void giveFlowers() {
this.pursuer.giveFlowers();
}
@Override
public void giveChocolate() {
this.pursuer.giveChocolate();
}
}
客户端代码如下。
public class Client {
public static void main(String[] args) {
SchoolGirl girl = new SchoolGirl("小静");
GiveGift proxy = new Proxy(girl);
proxy.giveDolls();
proxy.giveFlowers();
proxy.giveChocolate();
}
}
/**
运行输出如下:
[追求者]送给[小静]洋娃娃
[追求者]送给[小静]鲜花
[追求者]送给[小静]巧克力
*/
4.模式效果与应用
代理模式的使用场景如下
1)远程代理。为一个对象在不同的地址空间提供局部代表,从而隐瞒一个对象存在于不同地址空间的事实。
举例:在RPC调用中,会在client端创建一个server端接口的代理对象,这样client端调用远程server端的接口就像调用本地方法一样。
2)虚拟代理。对象实例化需要花费很长时间,可以临时用虚拟代理代替。
举例:我们访问一些网页时,常含有一些图片,如果图片很大,文本渲染完了,图片还没从服务器下载下来,这时,可以在网页上显示一个图片框,等到图片下载完了在显示真正的图片。
3)安全代理。用于控制对象的访问权限。
4)智能指引。调用真实的对象时,代理添加一些额外的操作。
举例:Spring AOP。
一句话总结:代理模式就是在访问对象时,引入了一定程度的间接性。