《Head First 设计模式》:代理模式
正文
一、定义
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
要点:
- 代理模式为一个对象创建了代理对象,让代理对象控制对该对象的访问。被代理的对象可以是远程的对象、创建开销大的对象或者需要安全控制的对象。
- 代理类型:远程代理、虚拟代理、保护代理等。
- 远程代理:控制访问远程对象。
- 虚拟代理:控制访问创建开销大的资源。
- 保护代理:基于权限控制对资源的访问。
二、实现步骤
1、创建主题接口
/**
* 主题接口
*/
public interface Subject {
/**
* 请求主题执行某种动作
*/
void request();
}
2、创建真实主题(被代理类),并继承主题接口
真实主题是真正做事的主题对象。
/**
* 真正做事的真实主题(被代理类)
*/
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject do something...");
}
}
3、创建主题代理(代理类),并继承主题接口
主题代理持有真正做事的真实主题,并控制对真实主题的访问。
/**
* 主题代理(代理类)
*/
public class SubjectProxy implements Subject {
/**
* 持有真实主题
*/
RealSubject realSubject;
@Override
public void request() {
System.out.println("SubjectProxy receives and controls request, and entrust request to RealSubject...");
// 代理并控制对真实主题的访问,比如权限控制、访问资源控制等
if (realSubject == null) {
realSubject = new RealSubject();
}
// ...
// 将请求委托给真实主题
realSubject.request();
}
}
4、使用主题代理访问主题
public class Test {
public static void main(String[] args) {
// 代理
SubjectProxy proxy = new SubjectProxy();
// 通过代理请求主题
proxy.request();
}
}
三、举个栗子
1、背景
我们打算建立一个应用程序,用来展示你最喜欢的 CD 封面。CD 封面的图我们可以从一些网站的在线服务中获取。
唯一的问题是,限于连接带宽和网络负载,下载可能需要一些时间,所以在等待图像加载时,应该显示一些东西。我们也不希望在等待图像时,整个应用程序被挂起。一旦图像被加载完成,刚才显示的东西应该消失,然后图像显示出来。
2、实现
使用虚拟代理管理图片的加载、显示。
(1)创建图片接口
/**
* 图片接口
*/
public interface Image {
/**
* 绘图
*/
void paint();
}
(2)创建真正做事的图片类
/**
* 真正进行图片操作的真实图片类
*/
public class RealImage implements Image {
String url;
String description;
public RealImage(String url, String description) {
this.url = url;
this.description = description;
load(url);
}
@Override
public void paint() {
System.out.println("Image is painted");
}
/**
* 模拟加载图片
*/
private void load(String url) {
try {
System.out.println("Loading image from: " + url);
for (int i = 0; i < 10; i++) {
System.out.print("===");
Thread.sleep(200);
}
System.out.println("===>100%");
System.out.println("Loading image is finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)创建图片代理
/**
* 图片代理
*/
public class ImageProxy implements Image {
RealImage realImage;
String imageUrl;
/**
* 是否已加载图片
*/
boolean hasLoaded = false;
public ImageProxy(String imageUrl) {
this.imageUrl = imageUrl;
}
@Override
public void paint() {
if (realImage != null) {
// 有图片,则直接绘图
realImage.paint();
} else {
// 没有图片,则先显示加载中的信息,再去加载并绘制图片
System.out.println("Loading CD cover, please wait...");
loadAndPaint();
}
}
/**
* 加载并绘制图片
*/
private void loadAndPaint() {
if (hasLoaded) {
return;
}
hasLoaded = true;
// 加载图片是一个比较耗时的操作,为了避免程序阻塞,采用异步处理
new Thread(new Runnable() {
@Override
public void run() {
realImage = new RealImage(imageUrl, "CD Cover");
// 加载完后,再进行绘图
realImage.paint();
}
}).start();
}
}
(4)使用图片代理进行绘图
public class Test {
public static void main(String[] args) throws InterruptedException {
// 图片代理
ImageProxy imageProxy = new ImageProxy("https://www.jingqueyimu.com/images/xxx.jpg");
// 使用图片代理进行绘图
System.out.println("首次绘图:");
imageProxy.paint();
Thread.sleep(3000);
System.out.println("再次绘图:");
imageProxy.paint();
}
}
四、Java 动态代理
1、创建主题接口
/**
* 主题接口
*/
public interface Subject {
/**
* 请求主题执行某种动作
*/
void request();
}
2、创建真实主题(被代理类),并继承主题接口
/**
* 真正做事的真实主题
*/
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject do something...");
}
}
3、使用 Java 动态代理,代理真实主题
public class Test {
public static void main(String[] args) {
// 真实主题(被代理类)
Subject realSubject = new RealSubject();
// 调用处理器
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理实例的方法被调用时,最终会执行该方法
System.out.println("InvocationHandler start to invoke...");
// do something...
// 调用真实主题(被代理类)的方法
method.invoke(realSubject, args);
// do something...
return null;
}
};
// 使用 Proxy 创建代理
Subject subjectProxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
// 通过代理发起请求
subjectProxy.request();
}
}
《Head First 设计模式》:代理模式的更多相关文章
- 9. 星际争霸之php设计模式--代理模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- C++设计模式——代理模式
前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就溜走了,现在上班的时候,偶尔还会怀念大学时,大家在一起玩游戏的时光.大学喜欢玩游戏,但是可悲的校园网,速度能把人逼疯了:还好,后来搞了一个 ...
- PHP设计模式-代理模式
概念理解: 代理模式,是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理对象取代,代理对象位于客户端和真实程序之间,指针有一个可被多个目标利用的钩子. 参与者: client(参与者) ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- 浅谈Python设计模式 - 代理模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...
- Java 之 设计模式——代理模式
设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...
- [Head First设计模式]抢票中的设计模式——代理模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- JAVA 设计模式 代理模式
用途 代理模式 (Proxy) 为其他对象提供一种代理以控制对这个对象的访问. 代理模式是一种结构型模式. 结构
- Java设计模式 - 代理模式
1.什么是代理模式: 为另一个对象提供一个替身或占位符以访问这个对象. 2.代理模式有什么好处: (1)延迟加载 当你需要从网络上面查看一张很大的图片时,你可以使用代理模式先查看它的缩略图看是否是自己 ...
- 深入浅出设计模式——代理模式(Proxy Pattern)
模式动机在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到 ...
随机推荐
- 【干货!!】三句话搞懂 Redis 缓存穿透、击穿、雪崩
前言 如何有效的理解并且区分 Reids 穿透.击穿和雪崩之间的区别,一直以来都挺困扰我的.特别是穿透和击穿,过一段时间就稀里糊涂的分不清了. 为了有效的帮助笔者自己,以及拥有同样烦恼的朋友们区分这三 ...
- Ubuntu安装Windows官方版QQ和微信(使用deepin wine)
- Resharper 2020 免费破解版
如果你是一名.NET开发人员,但是你却不使用ReSharper,那么你就不是一个合格的码农了,因为这是一个强大的神器,你值得拥有!当然,用它的代价是,启动VS会变得非常慢,非常卡,但是需要知道,磨刀不 ...
- cordova 环境配制和创建插件
环境配制 英文网站:http://cordova.apache.org/ 中文网站:http://cordova.axuer.com/ 安装Cordova Cordova的命令行运行在Node.js ...
- 【HttpRunner v3.x】笔记 ——4. 测试用例-结构解析
一.官方首推pytest格式 上篇文章我们知道了,httprunner可以支持三种格式的用例,分别是pytest.yaml和json.yaml和json是以前的版本所使用的用例格式,但是在3.x版本上 ...
- 给EmpMapper开放Restful接口
本文例程下载:https://files.cnblogs.com/files/xiandedanteng/gatling20200428-3.zip 接口控制器代码如下: 请求url和响应都写在了每个 ...
- Openresty使用
OpenResty是一个全功能的 Web 应用服务器.它打包了标准的 Nginx 核心,常用的第三方模块以及大多数依赖项. 可以把它看成是Nginx附加众多的第三方插件的合集.其主体是嵌入lua脚本的 ...
- netty如何进行单元测试
一种特殊的Channel 实现——EmbeddedChannel,它是Netty 专门为改进针对ChannelHandler 的单元测试而提供的. 将入站数据或者出站数据写入到EmbeddedChan ...
- Java的枚举简单应用
/** * 请用枚举方式实现如下应用: * 客户去旅店住房, * 客户分普通客户,和vip客户,vip分白金和钻石客户 * 不同的客户有不同的折扣 * 入住的房间分单人房,双人房和套房 * 不同的房间 ...
- [04] C# Alloc Free编程之实践
C# Alloc Free编程之实践 上一篇说了Alloc Free编程的基本理论. 这篇文章就说怎么具体做实践. 常识 之所以说是常识, 那是因为我们在学任何一门语言的时候, 都能在各种书上看到各种 ...