正文

一、定义

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

要点:

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

二、实现步骤

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. 数组的三种方式总结 多维数组的遍历 Arrays类的常用方法总结

    一.数组的三种声明方式总结 public class WhatEver { public static void main(String[] args) { //第一种 例: String[] tes ...

  2. vue项目在执行npm install时报错

    npm WARN registry Unexpected warning for https://registry.npmjs.org/: Miscellaneous Warning ETIMEDOU ...

  3. solrcloud集群版的搭建

    说在前面的话 之前我们了解到了solr的搭建,我们的solr是搭建在tomcat上面的,由于tomcat并不能过多的承受访问的压力,因此就带来了solrcloud的时代.也就是solr集群. 本次配置 ...

  4. 总结删除文件或文件夹的7种方法-JAVA IO基础总结第4篇

    本文是Java IO总结系列篇的第4篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  5. laravel+vue+vuetify 前端匹配不到数据记录 No matching records found

    后端数据:使用guzzle获取api数据,(安装扩展包guzzle) use GuzzleHttp\Client; //获取请求远程产品信息需要的参数public function getParams ...

  6. 趣味vi:Do you love me?

    看到网上有很多这样的小趣味exe,自己用labview也做了一个,可能有很多bug,马马虎虎能用,大家可以发给自己滴那个人,哈哈哈.源码vi和exe文件都在链接中https://files.cnblo ...

  7. Android studio Debug 源码

    原来有的地方打不了断点 会提示no executable code at line xxx 源码sdk里有,sdkManager下好对应版本,然后使用对应版本的模拟器debug就行了 如果要debug ...

  8. 分布式事务和分布式hash

    分布式事务是什么? 分布式事务就是保证各个微服务之间数据一致,本质上就是保证不同数据库的数据一致性.一致性状态包含 强一致性,任何时刻,所有节点中数据都是一样的 弱一致性,数据更新后,只能访问到部分节 ...

  9. Codeforces1365

    AC代码 A. Matrix Game 对于给定矩阵,剩余可用的位置的数目是确定的,根据奇偶性判断就完事了. B. Trouble Sort 如果数组\(b\)有0有1,那么Yes.否则只有数组\(a ...

  10. Tomcat cluster方案共享session配置成功,yeah....

    后继版本:https://www.cnblogs.com/xiandedanteng/p/12143112.html 参考网文: 1.Tomcat官方文档 2.https://blog.51cto.c ...