思考题

如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435

  • 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标类的代理对象(消费者)的方法,消费者内部将相关调用信息通过网络传到服务端对应的目标类的代理对象(生产者)中,生产者解析调用信息,然后真正去调用目标类的实际对象,并将返回结果回传给消费者,消费者再返回给客户端。 RPC 框架使用代理模式使得内部一系列处理及信息传输等对客户端和服务端是透明的,客户端会认为实际是本地调用一样,不知道调用了远程方法;服务端也不知道是在给远程对象提供服务。

思考题

远程调用程序应该完全透明吗?这是个好主意吗?这个方法可能会产生什么问题? P435

  • 远程调用程序不应该完全透明。由于引入了网络通信和数据处理(序列化、反序列化和压缩等),可能在相关过程会异常,客户端应该知晓并处理这些异常,而不应该让 RPC 框架消化掉这些异常而返回一些默认值。

代理模式

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

特点

  • 代理控制访问

    • 远程代理:控制访问远程对象 P460
    • 虚拟代理:控制访问创建开销大的资源 P460
    • 保护代理:基于权限控制对资源的访问 P460
    • 动态代理:在运行时动态地创建一个代理类,并将方法的调用转发到指定的类 P474
    • 防火墙代理:控制网络资源的访问,保护主题免于“坏客户”的侵害。多用于防火墙系统 P488
    • 智能引用代理:当主题被引用时,进行额外的动作,例如计一个对象被引用的次数。可用于对某些操作的日志记录 P488
    • 缓存代理:为开销大的运算结果提供暂时存储;也允许多个客户共享结果,以减少计算或网络延迟。多用于 Web 服务器代理,以及内容管理与出版系统 P488
    • 同步代理:在多线程的情况下为主题提供安全的访问。可用于 JavaSpaces ,为分散式环境内的潜在对象集合提供同步访问控制 P489
    • 复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度,并进行访问控制;有时候也成为外观代理,但与外观模式不同,因为代理控制访问,而外观模式只提供另一组接口 P489
    • 写入时复制代理:用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。这是虚拟代理的变体。CopyOnWriteArrayList 使用这种方式 P489

缺点

  • 代理会造成设计中类的数目增加 P491

代理模式和装饰器模式 P471

  • 代理模式控制对象的访问
  • 装饰器模式为对象增加行为

代理模式和适配器模式的区别 P471

  • 代理模式实现相同的接口(保护代理可能只提供给客户部分接口,与某些适配器很像)
  • 适配器模式改变对象适配的接口

思考题

class ImageProxy implements Icon {
// 实例变量构造器在这里
public int getIconWidth() {
if (imageIcon != null) {
return imageIcon.getIconWidth();
} else {
return 800;
}
} public int getIconHeight() {
if (imageIcon != null) {
return imageIcon.getIconHeight();
} else {
return 600;
}
} public void paintIcon(final Component c, Graphics g, int y, int y) {
if (imageIcon != null) {
imageIcon.paintIcon(c, g, x, y);
} else {
g.drawString("Loading CD cover, please wait...", x + 300, y + 190);
// 实例化 imageIcon 获取图片
}
}
}

以上为 CD 封面虚拟代理, ImageProxy 类似乎有两个,由条件语句控制的状态。你能否用另一个设计模式清理这样的代码?你要如何重新设计 ImageProxyP468

  • 可以用状态模式清理掉条件语句。设置两个状态 ImageNotLoadedImageLoaded ,分别将各个方法内条件语句内的代码放入这个两个状态的对应方法中,初始状态是 ImageNotLoaded ,当第一次调用 paintIcon 方法时,开始实例化 imageIcon 获取图片,成功后设置状态为 ImageLoaded

思考题

NonOwnerInvocationHandler 工作的方式除了它允许调用 setHotOrNotRating() 和不允许调用其他 set 方法之外,与 NonOwnerInvocationHandler 是很相似的。请写出 NonOwnerInvocationHandler 的代码: P482

import java.lang.reflect.*;

public class NonOwnerInvocationHandler implements InvocationHandler {
PersonBean person; public NonOwnerInvocationHandler(PersonBean person) {
this.person = person;
} public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try {
String methodName = method.getName();
if (methodName.startsWith("get")) {
return method.invoke(person, args);
} else if(methodName.equals("setHotOrNotRating")) {
return method.invoke(person, args);
} else if(methodName.startsWith("set")) {
throw new IllegalAccessException();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}

思考题

创建动态代理所需要的代码很短,请你写下 getNonOwnerProxy() ,该方法会返回 NonOwnerInvocationHandler 的代理。更进一步,请写下 getProxy() 方法,参数是 handlerperson ,返回值是使用此 handler 的代理。 P483

PersonBean getNonOwnerProxy(PersonBean person) {
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new NonOwnerInvocationHandler(person));
} PersonBean getProxy(InvocationHandler handler, PersonBean person) {
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), handler);
}

思考题

如何知道某个类是不是代理类? P486

  • JDK 动态代理的类是 Proxy 的子类,有一个静态方法 isProxyClass() ,此方法的返回值如果为 true ,表示这是一个动态代理类。
  • 【存疑】 代理类还会实现特定的某些接口
    • 在 Java8 中调用 proxy.getClass().getInterfaces() 及其他与获取接口有关的方法,并未发现实现新接口

思考题

能传入 newProxyInstance() 的接口类型,有没有什么限制?

  • 传入的接口数组内只能有接口,不能有类 P486
  • 如果接口不是 public ,就必须属于同一个 package P486
  • 【存疑】 不同的接口内,不可以有名称和参数完全一样的方法 P486
    • 经过 Java8 中实践确认没有此限制,不过永远只会识别为其中一个接口(接口数组内第一次出现该方法的接口)的方法
  • 接口数组内的接口可以不是被代理类实现的接口,代理类实现了接口数组内的所有接口,所有接口的调用都可以被拦截处理
  • 被代理类可以不实现任何接口,自己指定接口和相关调用处理逻辑也能使用

思考题

配对下列模式和描述: P487

代理模式:包装另一个对象,并控制对它的访问

外观模式:包装许多对象以简化它们的接口

装饰器模式:包装另一个对象,并提供额外的行为

适配器模式:包装另一个对象,并提供不同的接口

所思所想

  • 以前也看过不同动态代理的实现,但只是走马观花式地看一遍如何实现,没有实际去动手,这次读书时实际动手后感觉理解更深入了一点,大概更能了解内部是如何流转的
  • 实践是检验真理的唯一标准。书中存在部分说明可能错误或者不适用于当前版本,要利用好身边的工具,多实践操作,不能尽信书

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

Head First 设计模式 —— 13. 代理 (Proxy) 模式的更多相关文章

  1. 设计模式C++描述----13.代理(Proxy)模式

    一. 举例说明 我们有时打开一个网站时会发现有这样的现象,网站上的文字都显示出来了,但是上面的图片还没显示,要等一会才能显示. 这些未打开的图片的位置上,还是会有图片框和一些等待的信息的,这就是代理模 ...

  2. 十、设计模式之代理(Proxy)模式

    什么是代理模式 代理模式是对象的结构模式,为其他对象提供一种对象以控制对这个对象的访问. 代理模式的结构图如下:(源自大话设计模式)   Subject:定义了RealSubject和Proxy的公共 ...

  3. 设计模式 之代理(Proxy)模式

    为什么这里要定义代理呢?所谓代理代理,当然就是你不想做的事.找别人去做,这就是代理.所以,当你写代码的时候.你想保持类的简单性.重用性.你就能够把事件尽量都交给其他类去做.自己仅仅管做好自己的事.也就 ...

  4. JAVA设计模式-动态代理(Proxy)示例及说明

    在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理. 一,概念 代理设计模式的目的就是在不直接操作对象的前 ...

  5. JAVA设计模式-动态代理(Proxy)源码分析

    在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...

  6. C#设计模式(13)——代理模式(Proxy Pattern)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

  7. 代理(Proxy)模式简介

    Proxy 模式简介 代理模式的两个应用: 打开文档时加载大图片 例如:如果有个对象是一张很大的图片,而这张图片需要花费很长时间才能显示出来,那么当这个图片包含在文档中的后面时,使用编辑器或浏览器打开 ...

  8. C#设计模式(13)——代理模式(Proxy Pattern)(转)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

  9. 设计模式--代理(Proxy)模式

    在公司,经常性听到采购部的人说采购某样东材料,采购不了,需要通过代理商才可以.以前Insus.NET也做有一个练习<找人办事,代理设计模式(Proxy)>http://www.cnblog ...

随机推荐

  1. P5785 [SDOI2012]任务安排

    本题解用于本蒟蒻加深算法印象,也欢迎大家阅读 本篇题解将分为四块,一步一步地讲解本题, Part 1: O(n^3) \(n^3\) 算法应该非常的显然,我们设 \(f_{i,j}\) 为到 \(i\ ...

  2. JDK11 下载安装与配置环境变量

    1.jdk11本身也包含jre,不需要安装jre,低版本需要安装jre 2.jdk下载地址:https://www.oracle.com/technetwork/java/javase/downloa ...

  3. 【opencv】学习笔记

    安装 此笔记仅对python36实用 OpenCV装3.4.1.15 指令:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv ...

  4. 配置OSPF与BFD联动

    组网图形 OSPF与BFD联动简介 双向转发检测BFD(Bidirectional Forwarding Detection)是一种用于检测转发引擎之间通信故障的检测机制.BFD对两个系统间的.同一路 ...

  5. js下 Day20、综合案例

    一.购物车 效果图: 功能思路分析: 1. 面向对象框架 2. 模拟数据 1.多个店铺数组套对象 2.每个店铺多个商品,数组套对象

  6. 网站开发学习Python实现-Django项目部署-同步之前写的博客(6.2.2)

    @ 目录 1.说明 2.思路 3.代码 关于作者 1.说明 之前写的博客都在csdn和博客园中 要将博客同步到自己的博客网站中 因为都是使用markdown格式书写的,所以直接爬取上传就完事 2.思路 ...

  7. Web服务器-并发服务器-协程 (3.4.2)

    @ 目录 1.分析 2.代码 关于作者 1.分析 随着网站的用户量越来愈多,通过多进程多线程的会力不从心 使用协程可以缓解这一问题 只要使用gevent实现 2.代码 from socket impo ...

  8. 使用docker-maven-plugin打包

    今天在部署的时候遇到点问题,总结一下,docker部署的步骤,如果对您有帮助,关注一下,就是对我最大的肯定, 谢谢! 微服务部署有两种方法: (1)手动部署:首先基于源码打包生成jar包(或war包) ...

  9. 很多人不知道的Python 炫技操作:条件语句的写法

    有的人说 Python 是一门 入门容易,但是精通难的语言,这一点我非常赞同. Python 语言里有许多(而且是越来越多)的高级特性,是 Python 发烧友们非常喜欢的.在这些人的眼里,能够写出那 ...

  10. Java Int类型与字符,汉字之间的转换

    /** * java 中的流主要是分为字节流和字符流 * 再一个角度分析的话可以分为输入流和输出流 * 输入和输出是一个相对的概念 相对的分别是jvm虚拟机的内存大小 * 从另一个角度讲Java或者用 ...