代理设计模式的UML图:

我将首先介绍Java中的各种代理实现方法

Java代理设计模式 - 静态代理

这个例子非常简单,只有一个方法wirteCode的接口IDeveloper:

  1. public interface IDeveloper {
  2. public void writeCode();
  3. }
  4. // 实现这个接口的类:
  5. public class Developer implements IDeveloper{
  6. private String name;
  7. public Developer(String name){
  8. this.name = name;
  9. }
  10. @Override
  11. public void writeCode() {
  12. System.out.println("Developer " + name + " writes code");
  13. }
  14. }

测试代码:

  1. public class DeveloperTest {
  2. public static void main(String[] args) {
  3. IDeveloper jerry = new Developer("Jerry");
  4. jerry.writeCode();
  5. }
  6. }

测试输出:

  1. Developer Jerry writes code

现在麻烦的是,Jerry的领导因为团队中的开发者像Jerry一样没有编写技术文档,所以并不满意。经过讨论后,整个团队达成协议,相关文档必须与代码一起提供。

为了迫使开发人员编写文档而不直接对现有的实现类Developer进行修改,现在就可以使用静态代理来实现:

  1. // 创建一个和Developer类实现同样接口的类
  2. public class DeveloperProxy implements IDeveloper{
  3. private IDeveloper developer;
  4. // 引用Developer类对象
  5. public DeveloperProxy(IDeveloper developer){
  6. this.developer = developer;
  7. }
  8. @Override
  9. public void writeCode() {
  10. System.out.println("Write documentation...");
  11. this.developer.writeCode();
  12. }
  13. }

测试代码:

  1. public class DeveloperTest {
  2. public static void main(String[] args) {
  3. Developer jerry = new Developer("jerry");
  4. DeveloperProxy jerryproxy = new DeveloperProxy(jerry);
  5. jerryproxy.writeCode();
  6. }
  7. }

测试输出:

  1. Write documentation...
  2. Developer jerry writes code

静态代理的优点

假设你希望在不修改原始类代码的情况下增强现有的稳定实现,你可以创建一个代理类,并将原始实现封装为代理中的私有属性。增强的功能是在代理类中完成的,对现有的代码是完全透明的。回到上面的示例,客户端代码并不关心它用来调用writeCode()方法的变量是否指向真正的开发人员或开发人员代码。

优点:

  1. 易于实施和理解
  2. 原始实现与其代理之间的关系在编译时已经确定,运行时没有额外的开销。

静态代理的缺点

我们仍然使用这个例子来说明。

假设现在缺失文档的问题在QA同事中仍然存在。如果我们想通过静态代理来解决这个问题,那么必须引入另一个代理类。

这是测试人员的接口:

  1. public interface ITester {
  2. public void doTesting();
  3. }
  4. // ITester 接口的实现类:
  5. public class Tester implements ITester {
  6. private String name;
  7. public Tester(String name){
  8. this.name = name;
  9. }
  10. @Override
  11. public void doTesting() {
  12. System.out.println("Tester " + name + " is testing code");
  13. }
  14. }

测试人员代理:

  1. public class TesterProxy implements ITester{
  2. private ITester tester;
  3. public TesterProxy(ITester tester){
  4. this.tester = tester;
  5. }
  6. @Override
  7. public void doTesting() {
  8. System.out.println("Tester is preparing test documentation...");
  9. tester.doTesting();
  10. }
  11. }

测试代码和输出:

从Tester代理的源代码中我们可以很容易的观察到它与开发人员具有完全相同的逻辑。如果又过了一段时间,我们必须为软件交付过程中的其他同事建立文档,我们必须一次又一次的引入新的静态代理类,这会导致静态代理类变得十分庞大。

Java中的动态代理 - 调用处理器

现在我通过代理类EnginnerProxy来为所有的具体角色提供代理服务,而不是单独为每个原始实现类设置专用的静态代理类。

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. public class EnginnerProxy implements InvocationHandler
  5. {
  6. Object obj;
  7. public Object bind(Object obj)
  8. {
  9. this.obj = obj;
  10. return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
  11. .getClass().getInterfaces(), this);
  12. }
  13. @Override
  14. public Object invoke(Object proxy, Method method, Object[] args)
  15. throws Throwable
  16. {
  17. System.out.println("Enginner writes document");
  18. Object res = method.invoke(obj, args);
  19. return res;
  20. }
  21. }

主要笔记:

  1. 不是从具有业务接口(IDeveloper或ITester)的专用接口继承,而是在此变体中,通过代理继承自JDK提供的技术接口InvocationHandler
  2. 为了确保通用代理可以适用于所有可能的具体实现类,在代理中定义了具有泛型类型的Object变量。
  3. 调用代理实例的接口方法时,它将被InvocationHandler中定义的invoke方法拦截,其中由应用程序开发人员声明的增强逻辑与由Java Reflection调用的原始逻辑一起调用。

下面是如何使用InvocationHandler设计的动态代理和测试输出:

动态代理类的限制

虽然这个变体成功的避免了静态代理中的重复缺陷,但是它仍然有一个局限性,它无法使用不是从接口继承的实现类,就是说,使用动态代理类,原始类必须先要实现一个或多个接口,这个接口也就是代理接口。

考虑下面的例子,产品所有者没有实现任何接口:

  1. public class ProductOwner {
  2. private String name;
  3. public ProductOwner(String name){
  4. this.name = name;
  5. }
  6. public void defineBackLog(){
  7. System.out.println("PO: " + name + " defines Backlog.");
  8. }
  9. }

以下代码在IDE中没有任何语法错误:

  1. ProductOwner po = new ProductOwner("Ross");
  2. ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);
  3. poProxy.defineBackLog();

不幸的是编译时报出了以下错误:

Java动态代理模式浅析的更多相关文章

  1. Java 动态代理模式浅析

    目录 Java代理设计模式 - 静态代理 静态代理的优点 静态代理的缺点 Java中的动态代理 - 调用处理器 主要笔记: 动态代理类的限制 代理设计模式的UML图: 我将首先介绍Java中的各种代理 ...

  2. JAVA动态代理模式(从现实生活角度理解代码原理)

    所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...

  3. 关于java动态代理模式

    1. 动态代理 动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联. 动态代理主要用到java.lang.reflect包中的两个类,Invocation ...

  4. java动态代理模式

    java动态代理机制详解 Spring的核心AOP的原理就是java的动态代理机制. 在java的动态代理机制中,有两个重要的类或接口: 1.InvocationHandler(Interface): ...

  5. java 动态代理模式(jdk和cglib)

    package proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Met ...

  6. java jdk动态代理模式举例浅析

    代理模式概述 代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色. java中常用的动态代理模式为jdk动态代理和c ...

  7. JAVA代理模式与动态代理模式

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某 ...

  8. Java设计模式系列之动态代理模式(转载)

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Sub ...

  9. Java静态代理与动态代理模式的实现

    前言:    在现实生活中,考虑以下的场景:小王打算要去租房,他相中了一个房子,准备去找房东洽谈相关事宜.但是房东他很忙,平时上班没时间,总找不到时间去找他,他也没办法.后来,房东想了一个办法,他找到 ...

随机推荐

  1. Konckout第三个实例:循环绑定 -- table列表数据的填充

    传统js:拼接字符串,再写入指定标签中 <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...

  2. Javascript中几个看起来简单,却不一定会做的题

    Javascript作为前端开发必须掌握的一门语言,因为语言的灵活性,有些知识点看起来简单,在真正遇到的时候,却不一定会直接做出来,今天我们就一起来看看几道题目吧 题目1 var val = 'smt ...

  3. C#中的String类

    一.String类的方法 1. Trim():清除字符串两端的空格 2. ToLower():将字符串转换为小写 3. Equals():比较两个字符串的值,bool 4. IndexOf(value ...

  4. 初始配置JDK

    什么是java? java是一门编程语言  编程语言有很多种 你比如 C语言 等等 为什么学习java呢! 因为你要和计算机交互  当然了你用汉语跟她说她听不懂 所以你要学习编程语言 那么额咱们的ja ...

  5. IntelliJIDEA中如何使用JavaDoc

    IntelliJ IDEA 12.1.6,本身提供了很好的 JavaDoc 生成功能,以及标准 JavaDoc 注释转换功能,其实质是在代码编写过程中,按照标准 JavaDoc 的注释要求,为需要暴露 ...

  6. 测试与发布(Beta版本)

    评分基准: 按时交 - 有分(测试报告-10分,发布说明-10分,展示博客-10分),检查的项目包括后文的两个方面 测试报告(基本完成5分,根据完成质量加分,原则上不超过满分10分) 发布说明(基本完 ...

  7. 201621123062《Java程序设计》第一周学习总结

    1.本周学习总结 关键词: 初步熟悉Java的基本组成.语言特点(简单性.结构中立性).运行环境.简单语法等. 关键概念之间的联系: 1.JVM是Java程序唯一认识的操作系统,其可执行文件为.cla ...

  8. NetFPGA-1G-CML Demo --- openflow_switch

    环境 ubuntu 14.04 vivado 15.2 ise 14.6 更多基础配置:http://www.cnblogs.com/wpqwpq/p/6771568.html 运行步骤 step1: ...

  9. 多线程socket UDP收发数据

    多线程socket收发数据 from threading import Thread from socket import * def sendData(): while True: sendInfo ...

  10. 手把手教你 LabVIEW 串口仪器控制——VISA 驱动下载安装篇

           仪器控制,核心在于 VISA 函数..有些仪器可能不需要 VISA,有自己的 DLL 什么的,我就管不着.        正常情况下,大家安装的 LabVIEW,都是不带 VISA 驱动 ...