本篇文章是对自己学习的一个总结,学习资料来源是大话设计模式,程杰著,清华大学出版社出版
代理模式其实还挺简单,我之前写过jdk动态代理(大家看看这篇博客里的静态代理,理解代理模式就变得非常容易),里面的静态代理其实就是代理模式。但是这段时间看了程杰的设计模式之后,才将代理模式给抽象化。然后也突然想到原来代理模式还可以这样用。
代理模式UML类图如下所示。
这个UML类图与书上的略有不同,因为我觉得代理模式重点是对realSubject的代理,代理的动作不一定要涉及到其他类,所以我将UML类图简化成现在这样。
代理模式的理念就是用对真是对象的一些行为做代理,将这些行为交给代理做,不用真实对象直接出面。这样的话,代理类在执行代理方法的时候,就可以对真是对象的行为进行一些限制或者增强。
因为代理是代理真实对象的某些方法,所以他们的应该具有同样的方法。比如真实对象有买菜这个行为,代理类代理买菜,那也应该具有买菜这个方法。这样的话,我们就将代理类代理的方法抽出来变成一个接口,让代理类和真实对象都去实现这个接口。这个接口里的方法就是真是对象希望被代理的方法。所以subject接口中所有的方法就是realSubject希望被代理的方法。
因为所有行为都是真实对象通过代理发出的,即实际发出者是真实对象,不是代理。所以代理类中需要有真实对象的引用,不然都无法知道是哪个真实对象想代理方法。于是就有了下面完整的UML类图。
之前也说道,代理在代理行为时,会对真实对象的方法进行一些限制或加强,这也是我们使用代理模式的原因。
比如被代理的方法是买菜,那代码如下所示
interface Subject{
public void abstract buyFood();
}
class RealSubject implements Subject{
@Override
public void buyFood(){
付钱得到商品···;
}
}
class Proxy implements Subject{
private RealSubject realSubject;
Subject(RealSubject realSubject){
this.realSubject = realSubject;
}
@Override
public void buyFood(){
寻找便宜的菜市场···;
realSubject.buyFood();
}
}
public static void main(String[] args){
RealSubject someone = new RealSubject();
Proxy proxy = new Proxy(someone);
proxy.buyFood();
}
上面的代码中,真正像买菜的人是someone,这个人买菜的动作就是付钱拿菜。但是如果他将买菜交给一个代理去做,那代理就会在他付钱买菜之前先找到便宜的菜市场,然后再付钱买菜。这里代理就是对代理行为进行了加强。
我们可以假设一个场景,一个真实对象想访问一个链接,那么它的行为内容就应该是“点击,打开链接”。但是这样安全性不够,于是我们对访问链接这个行为进行代理,在“点击,打开链接”之前我们对链接进行安全性检查,高危网站就不能打开(直接return,不执行realSubject.visit()方法)。这样真实对象的访问操作就被我们限制了(不是想打开什么链接都可以)。这就是通过代理对真实对象行为的限制。
讲到这里对代理模式就应该了解得差不多了,原本我想在这里结束这篇博客,但是书中举了一个例子我觉得非常好,所以我想在这里再说一下。
网站开发里有一种技术叫虚拟代理,就是当需要创建开销很大的对象时(比如打开一个网页,要下载大量图片),可以通过代理来存放实例化需要很长时间的真实对象。
我对这个例子的理解是真实对象的行为是下载图片然后输出到页面,代理则是在图片完全下载完之前就先输出一个和图片大小一样的白框。
class RealSubject implements Subject{
@Override
public void showPictures(){
下载所有图片并输出;
}
}
class Proxy implements Subject{
private RealSubject realSubject;
Subject(RealSubject realSubject){
this.realSubject = realSubject;
}
@Override
public void buyFood(){
先获取图片的大小,然后输出和图片大小一样大的白框;
realSubject.showPictures();
}
}
public static void main(String[] args){
Proxy proxy = new Proxy();
RealSubject someone = new RealSubject();
proxy.showPictures();
}
这样的话,浏览网页时,及时网速不是很给力,但也能改善一些体验。具体情况如下所示