正文

一、定义

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

要点:

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

二、实现步骤

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. Lambda 表达式推演全过程

    Java 的 Lambda 表达式推演过程: 第一步:正常的类实现(外部实现),new一个对象,然后重写方法实现 public class TestLambda3 { public static vo ...

  2. 轻松应对并发,Newbe.Claptrap 框架入门,第四步 —— 利用 Minion,商品下单

    接上一篇 Newbe.Claptrap 框架入门,第三步 —— 定义 Claptrap,管理商品库存 ,我们继续要了解一下如何使用 Newbe.Claptrap 框架开发业务.通过本篇阅读,您便可以开 ...

  3. MYSQL经典练习题,熟悉DQL

    MYSQL经典练习题 (本练习题可让你熟悉DQL,快速的上手DQL) 首先,先在数据库中建立基本数据库以及表项: DROP DATABASE IF EXISTS `test`; CREATE DATA ...

  4. 百度支持链接的nofollow属性吗

    http://www.wocaoseo.com/thread-269-1-1.html 简单明确的一个问题,百度目前支持链接的nofollow属性吗?rel='external nofollow' 复 ...

  5. React.Fragment

    React 中一个常见模式是为一个组件返回多个元素.Fragments 可以让你聚合一个子元素列表,并且不在DOM中增加额外节点. Fragments 看起来像空的 JSX 标签: render() ...

  6. Xutils 的框架问题retry error, curr request is null Android开发之网络请问问题

    没有网络权限也能导致这个问题 也可能是因为模拟机没联网的问题

  7. 【小白学PyTorch】6 模型的构建访问遍历存储(附代码)

    文章转载自微信公众号:机器学习炼丹术.欢迎大家关注,这是我的学习分享公众号,100+原创干货. 文章目录: 目录 1 模型构建函数 1.1 add_module 1.2 ModuleList 1.3 ...

  8. 16_Python设计模式

    1.设计模式概述 1.设计模式代表了一种最佳的实践,是被开发人员长期总结,用来解决某一类问题的思路方法,这些方法保证了代码的效率也易于理解 2.设计模式类型:根据23种设计模式可以分为三大类     ...

  9. Python3 字典浅析

    Python 字典 字典(Dictionary) 字典是一个无序.可变和有索引的集合.在 Python 中,字典用花括号编写,拥有键和值. 实例 创建并打印字典: thisdict = { " ...

  10. Java 根据两个经纬度,得到两点距离

    private static final double EARTH_RADIUS = 6371000;//赤道半径(单位m)private static final double INTEGR_NUM ...