代理设计模式的UML图:

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

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

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

public interface IDeveloper {
public void writeCode();
}
// 实现这个接口的类:
public class Developer implements IDeveloper{
private String name;
public Developer(String name){
this.name = name;
}
@Override
public void writeCode() {
System.out.println("Developer " + name + " writes code");
}
}

测试代码:

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

测试输出:

Developer Jerry writes code

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

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

// 创建一个和Developer类实现同样接口的类
public class DeveloperProxy implements IDeveloper{
private IDeveloper developer;
// 引用Developer类对象
public DeveloperProxy(IDeveloper developer){
this.developer = developer;
}
@Override
public void writeCode() {
System.out.println("Write documentation...");
this.developer.writeCode();
}
}

测试代码:

public class DeveloperTest {
public static void main(String[] args) {
Developer jerry = new Developer("jerry");
DeveloperProxy jerryproxy = new DeveloperProxy(jerry);
jerryproxy.writeCode();
}
}

测试输出:

Write documentation...
Developer jerry writes code

静态代理的优点

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

优点:

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

静态代理的缺点

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

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

这是测试人员的接口:

public interface ITester {
public void doTesting();
}
// ITester 接口的实现类:
public class Tester implements ITester {
private String name; public Tester(String name){
this.name = name;
}
@Override
public void doTesting() {
System.out.println("Tester " + name + " is testing code");
}
}

测试人员代理:

public class TesterProxy implements ITester{
private ITester tester;
public TesterProxy(ITester tester){
this.tester = tester;
}
@Override
public void doTesting() {
System.out.println("Tester is preparing test documentation...");
tester.doTesting();
}
}

测试代码和输出:

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

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

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

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class EnginnerProxy implements InvocationHandler
{
Object obj;
public Object bind(Object obj)
{
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("Enginner writes document");
Object res = method.invoke(obj, args);
return res;
}
}

主要笔记:

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

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

动态代理类的限制

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

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

public class ProductOwner {
private String name;
public ProductOwner(String name){
this.name = name;
}
public void defineBackLog(){
System.out.println("PO: " + name + " defines Backlog.");
}
}

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

ProductOwner po = new ProductOwner("Ross");
ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);
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. centos安装postgis

      step 1   yum localinstall https://download.postgresql.org/pub/repos/yum/9.2/redhat/rhel-7-x86_64/p ...

  2. android中activity.this跟getApplicationContext的区别

    转载: http://www.myexception.cn/android/1968332.html android中activity.this和getApplicationContext的区别 在a ...

  3. Python下载图片小程序

    欢迎大侠们指正批评 思路: 1.引入相关的python文件(import re  import urllib) 2.读取对应网页的html文件(使用 urllib) def getHtml(url): ...

  4. 【Java】0X001.配置开发环境,JDK、classpath等

    [Java]0x01 配置开发环境,JDK.CLASSPATH等 一. 下载JDK安装文件 首先,进入Oracle官网Java页面. 注意,要下载的是JDK而不是JRE,这点很重要,因为JRE并不包含 ...

  5. Alpha第三天

    Alpha第三天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  6. Beta冲刺NO.3

    Beta冲刺 第三天 1. 昨天的困难 1.昨天的困难主要集中在对Ajax的使用上,不熟悉这种语法,所以也就浪费了时间,导致昨天的批量删除没有完全完成. 2.由于之前的网页构造style很乱,导致修改 ...

  7. 高级软件工程2017第3次作业——结对项目:四则运算题目生成程序(基于GUI)

    Deadline:2017-10-11(周三)21:00pm (注:以下内容参考集大作业 ) 前言 想过和别人一起探索世界吗?多么希望,遇到困难时,有人能一起探讨:想要懈怠时,有人推你一把:当你专注于 ...

  8. 项目Alpha冲刺Day4

    一.会议照片 二.项目进展 1.今日安排 学习熟悉前台框架且搭建前台页面框架. 2.问题困难 使用了前端的构建工具webpack,困难在于怎么使用gradle结合它连同后台框架中的配置一起打包,因为本 ...

  9. 201421123042 《Java程序设计》第11周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 源代码阅读:多线程程序BounceThread 1.1 BallR ...

  10. python 操作SQLAlchemy

    SQLAlchemy python链接 pymysql mysql+pymysql://<username>:<password>@<host>/<dbnam ...