设计模式系列往期文章
- 设计模式学习之策略模式
- 设计模式学习之策略模式在前端的应用
- 设计模式学习之简单工厂模式
- 设计模式学习之工厂方法模式
- 设计模式学习之抽象工厂模式
- 设计模式学习之策略模式和简单工厂模式的对比
- 设计模式学习之观察者模式
- 设计模式学习之模板方法模式
代理模式是结构型设计模式的一种,如下图所示——这种设计模式通过提供一个代理供调用方使用,代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
应用场景
当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
举个栗子
某程序库提供了视频下载类。 但是该类的效率非常低。 如果客户端程序多次请求同一视频, 程序库会反复下载该视频, 而不会将首次下载的文件缓存下来复用。
这个时候就可以添加一个代理类(这个代理类实现和原视频下载类相同的接口),该代理类将所有工作委派给原下载器。不过代理类也不是什么都不做,代理类能够保存所有的文件下载记录, 如果程序多次请求同一文件, 它会返回缓存的文件,这样便可以完成优化。
说明:因此代理类相当于在被代理类的基础上做了一层封装,可以额外添加一些属性或者方法。
对应的类图为:
实现伪代码如下:
/** 三方视频下载接口 */
public interface ThirdPartyTVLib {
List<Video> listVidos();
Video getVideoInfo(String videoId);
Video downloadVideo(String videoId);
}
/** 三方视频下载类 */
public class ThirdPartyTVClass implements ThirdPartyTVLib {
@Override
public List<Video> listVidos() {
// TOOD
}
@Override
public Video downloadVideo(String videoId) {
// TODO
}
@Override
public Video getVideoInfo(String videoId) {
connectToServer("http://www.youtube.com/" + videoId);
return getSomeVideo(videoId);
}
private int random(int min, int max) {
return min + (int) (Math.random() * ((max - min) + 1));
}
private void connectToServer(String server) {
System.out.print("Connecting to " + server + "... ");
experienceNetworkLatency();
System.out.print("Connected!" + "\n");
}
private Video getSomeVideo(String videoId) {
System.out.print("Downloading video... ");
Video video = new Video(videoId, "Some video title");
System.out.print("Done!" + "\n");
return video;
}
}
/** 代理类 */
public class CachedTVClass implements ThirdPartyTVLib {
private HashMap<String, Video> cache = new HashMap<String, Video>();
private ThirdPartyTVLib thirdPartyTVLib;
public CachedTVClass() {
this.thirdPartyTVLib = new ThirdPartyTVClass();
}
@Override
public Video getVideoInfo(String videoId) {
Video video = cache.get(videoId);
if (video == null) {
video = thirdPartyTVLib.getVideo(videoId);
cacheAll.put(videoId, video);
} else {
System.out.println("Retrieved video '" + videoId + "' from cache.");
}
return video;
}
@Override
public List<Video> listVidos() {
// TOOD
}
@Override
public Video downloadVideo(String videoId) {
// TODO
}
public void reset() {
cache.clear();
}
}
UML图
对应的plantUML代码:
@startuml
skinparam linetype ortho
package "Proxy" <<Frame>> {
interface Subject {
+ method()
}
class RealSubject {
+ method()
}
class ProxySubject {
- subject: RealSubject
+ method()
+ otherMethod()
}
class Client {
}
note right of Client
// Client直接调用代理类
subject = new ProxySubject();
subject.method();
end note
note right of ProxySubject
// 在代理类中保存了一个被代理类的实例
end note
Subject <|.. RealSubject
Subject <|.. ProxySubject
RealSubject <-- ProxySubject
Client ..> Subject
}
@enduml