正文

一、定义

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。

要点:

  • 代理模式为一个对象创建了代理对象,让代理对象控制对该对象的访问。被代理的对象可以是远程的对象、创建开销大的对象或者需要安全控制的对象。
  • 代理类型:远程代理、虚拟代理、保护代理等。
    • 远程代理:控制访问远程对象。
    • 虚拟代理:控制访问创建开销大的资源。
    • 保护代理:基于权限控制对资源的访问。

二、实现步骤

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 设计模式》:代理模式的更多相关文章

  1. 9. 星际争霸之php设计模式--代理模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  2. C++设计模式——代理模式

    前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就溜走了,现在上班的时候,偶尔还会怀念大学时,大家在一起玩游戏的时光.大学喜欢玩游戏,但是可悲的校园网,速度能把人逼疯了:还好,后来搞了一个 ...

  3. PHP设计模式-代理模式

    概念理解: 代理模式,是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理对象取代,代理对象位于客户端和真实程序之间,指针有一个可被多个目标利用的钩子. 参与者: client(参与者) ...

  4. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  5. 浅谈Python设计模式 - 代理模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...

  6. Java 之 设计模式——代理模式

    设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...

  7. [Head First设计模式]抢票中的设计模式——代理模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  8. JAVA 设计模式 代理模式

    用途 代理模式 (Proxy) 为其他对象提供一种代理以控制对这个对象的访问. 代理模式是一种结构型模式. 结构

  9. Java设计模式 - 代理模式

    1.什么是代理模式: 为另一个对象提供一个替身或占位符以访问这个对象. 2.代理模式有什么好处: (1)延迟加载 当你需要从网络上面查看一张很大的图片时,你可以使用代理模式先查看它的缩略图看是否是自己 ...

  10. 深入浅出设计模式——代理模式(Proxy Pattern)

    模式动机在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到 ...

随机推荐

  1. asyncio系列之Lock实现

    import types import select import time import socket import functools import collections class Futur ...

  2. Istio的流量管理(实操三)

    Istio的流量管理(实操三) 涵盖官方文档Traffic Management章节中的egress部分.其中有一小部分问题(已在下文标注)待官方解决. 目录 Istio的流量管理(实操三) 访问外部 ...

  3. 医疗seo常用的图标工具

    http://www.wocaoseo.com/thread-304-1-1.html 下面是一些医疗seo常用的一些图表工具,这些都是些最简单的工具,主要放置这里以防止以后有作用. 1,医疗的常用搜 ...

  4. WebApi之DOM的基本介绍

    1.1.1 什么是DOM ​ 文档对象模型(Document Object Model,简称DOM),是 W3C 组织推荐的处理可扩展标记语言(html或者xhtml)的标准编程接口. ​ W3C 已 ...

  5. Docker 镜像的备份恢复迁移

    在大家已经学会了如何构建镜像以后,为了备份该镜像,我们有以下几个选择: 我们可以将指定镜像保存成 tar 归档文件,需要使用时将 tar 包恢复为镜像即可: 登录 DockerHub 注册中心,将镜像 ...

  6. e3mall商城总结13之订单确认(有BUG)

    说在前面的话 上一节说了购物车的生成,本节主要说了在购物车的列表上去结算,从而生成一个未支付的订单,生成的订单默认状态为1, 题目说的BUG是因为所有数据都是通过前端向后端生成的,包括订单的金额.因此 ...

  7. Nodejs模块:fs

    /** * @description fs模块常用api */ // fs所有的文件操作都是异步IO,如果要以同步的方式去调用,都会加一个在原同步api的基础上加Sync // 同步的方式会在最后传入 ...

  8. Android开发java开发之常用英文词汇汇总。程序员必备英语单词

    ANR  (Application Not Response )  bundle 捆, entire 整个的,完整的 lifetime 生命周期 entire lifetime 完整生命周期 visi ...

  9. 跨平台C# UI库

    https://github.com/AvaloniaUI/Avalonia https://www.cnblogs.com/leolion/p/7144896.html https://github ...

  10. 剑指 Offer 54. 二叉搜索树的第k大节点

    题目描述 给定一棵二叉搜索树,请找出其中第k大的节点. 示例1: 输入: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 输出: 4 示例2: 输入: root ...