理解设计模式之代理模式

本贴最后更新于 2334 天前,其中的信息可能已经时过境迁

代理模式 Proxy Pattern

  什么是代理模式?首先理解代理这个词,从概念上讲有代理人与被代理人之分,代理人替被代理人办事。那么从程序的角度上讲,就是代理类,对真实的类,进行逻辑功能增强。之前讲过装饰模式,装饰模式也是对一个类进行增强,那么装饰模式和代理模式到底有什么不同?首先,两者的业务出发点不同,装饰模式主要是理解被装饰对象方法的业务逻辑,并对其进行扩展增强,而代理模式并不关心你这个对象内部方法的业务逻辑是什么,而只关心你调用了什么方法,对你调用的方法进行拦截控制,进行额外的业务处理。其次两者的实现方式不一样,装饰模式实现难度小,代理模式实现难度大,不过目前已经有很多开源的工具供我们使用,我们只需要实现具体的代理逻辑即可。

代理模式的实现

  代理模式的实现我看网上资料分为静态代理和动态代理,说实话,我觉得静态代理不太合理,实现方式跟装饰模式没有太大不同,有些人说构造函数中直接分配代理对象,就是静态代理,我觉得这种方式有点牵强。首先违背开闭原则,代理类还要实现与被代理类的接口?这相当于跟业务进行了绑定,业务接口改变,代理类会跟着改变,这既不符合开闭原则,又与代理模式的设计理念相违背,代理根本不关心你这个类有多少个方法,我只关心你调用了何种方法,除非你新增的方法跟代理业务有关,否则根本不用管,但是静态代理就打破了这种模式,所以我觉得静态代理不合理。
  我觉得动态代理才是代理模式的精髓,有第三方工具来辅助动态代理的实现,首先是 Java 的标准实现:
1、接口定义

public interface Subject { public String getName(); public void setName(String name); public int getAge(); public void setAge(int age); }

2、接口的实现对象

public class RealSubject implements Subject{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

3、代理拦截器实现

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { private Object subject; public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { String methodName = method.getName(); System.out.println("调用的方法:" + methodName); if ("setName".equals(methodName)) { args[0] = args[0] + "-Proxy"; } Object obj = method.invoke(subject, args); return obj; } }

4、测试类

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxyTest { public static void main(String[] args) { RealSubject person = new RealSubject(); InvocationHandler handler = new DynamicProxy(person); Subject proxy = (Subject) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), handler); System.out.println(proxy.getClass()); proxy.setName("michael"); System.out.println(proxy.getName()); } }

  从上面可以看出,具体的代理拦截器中,代理了具体对象的方法执行,对其进行拦截处理,这是不是跟我们常见的一个词很相似?这个词就是 AOP,面向切面的编程,没错,就是这个玩意。面向切面的编程就是根据方法拦截器来实现的,当然有其他第三方工具包来辅助,例如 cglib。下面是基于 cglib 的方式来实现动态代理:
1、方法拦截器

import java.lang.reflect.Method; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class CglibMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { String methodName = method.getName(); System.out.println("before method " + methodName); Object result = proxy.invokeSuper(obj, args); System.out.println("after method " + methodName); return result; } }

2、测试类

import org.springframework.cglib.proxy.Enhancer; public class CglibTest { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback(new CglibMethodInterceptor()); RealSubject obj = (RealSubject) enhancer.create(); System.out.println(obj.getClass()); obj.setName("michael"); System.out.println(obj.getName()); } }

  这里可以看到,基于 cglib 的方式要比 java 原生的方便很多,spring 的 AOP 就是基于这种方式来实现的。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3192 引用 • 8214 回帖 • 2 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖
  • 安全

    安全永远都不是一个小问题。

    204 引用 • 816 回帖 • 2 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    132 引用 • 796 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 642 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 489 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 71 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 243 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖 • 1 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖 • 3 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 491 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 2 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 655 关注
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    93 引用 • 901 回帖
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖 • 4 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    421 引用 • 1247 回帖 • 591 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 586 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 697 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 2 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 167 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 487 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖 • 2 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 4 关注
  • Visio
    1 引用 • 2 回帖
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    20 引用 • 7 回帖 • 3 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖