代理设计模式的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. 简单谈谈DNS的工作原理及实践

    DNS协议简介 dns(Domain Name System)是一个全球化的分布式数据库系统,用于存储域名和互联网IP地址的映射关系.dns协议是计算机协议栈应用层中,应用最广泛的协议之一.用户每一次 ...

  2. 【Redis使用系列】redis设置登陆密码

    找到安装redis的配置文件,找到redis.comf文件找到#requirepass foobared 新建一行 requirepass  xxxx 你的密码 ,然后重启.再登录的时候可以登录,但是 ...

  3. Alpha冲刺No.6

    站立式会议 继续页面设计 在安卓内构件数据库相应类 解决摄像头.照片的使用的异常问题 二.实际项目进展 页面设计完成百分80 类架构完成 在虚拟机中,能够完成摄像头的调用和程序的使用 三.燃尽图 四. ...

  4. collections deque队列及其他队列

    from collections import deque dq = deque(range(10),maxlen=10) dq.rotate(3)#队列旋转操作接受一个参数N,让N>0时,队列 ...

  5. Django 测试驱动开发

    第一章 1.编写functional_tests.py from selenium import webdriver browser = webdriver.Firefox() browser.get ...

  6. 201621123027 《Java程序设计》第1周学习总结

    01621123027 <Java程序设计>第1周学习总结 1.本周学习总结 关键词:总概.承接.面向对象化 ​ 我认为第一周的Java学习是一些总结概括性质的内容,在比较联系之前学习过的 ...

  7. 个人技术博客(alpha)

    APP的权限校验不同于web网页端,web一般使用session记录用户的状态信息,而app则使用token令牌来记录用户信息.有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在 ...

  8. 十、Python练习----基础搭建飞机大战

    只是简单的学习了pygame,实现飞机的摧毁还需要多张图片的切换,和sprite(碰撞精灵),还有多种音效的添加(如背景音乐.摧毁特效).以后再深入学习我只是练习一下python. 一.搭建界面(基于 ...

  9. $.ajax 提交数据到后台.

    //AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML -- (Extensible Markup Language 可扩展标记语言 ...

  10. hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(2)安装hadoop

    一.依赖安装 安装JDK 二.文件准备 hadoop-2.7.3.tar.gz 2.2 下载地址 http://hadoop.apache.org/releases.html 三.工具准备 3.1 X ...