外观模式和代理模式的联系和区别_Java设计模式:代理模式和装饰模式的异同剖析...

背景

笔者前几天看了一个面试题 “说一下什么是代理模式?”,于是回忆了一下这个设计模式,并结合一篇旧文 《理理 Java 开发中常见的设计模式》,温故了一下这个知识点。

十年前看了好多遍的设计模式,死活处于学了忘、学不会的状态;如今随便翻到的某个 Java 技术点,都能快速反应出它们的前因后果。时光如梭,毕业已经十年了,这大概算是进入了卖油翁纯熟的技艺阶段了吧!

代理模式概述

代理模式类图。面向对象编程语言中,代理对象和委托对象都需要实现相同接口,同时代理对象关联一个真正的委托对象,客户端得到的是一个代理的引用,实则背后调用的是真正委托对象的方法:

60e0fb205e69546f47fd328132580099.png

代理类型。 对于有大量类需要代理的应用,这就是一种负担。一方面增加了工作量,而且还产生了大量相似的代理类,所以有了动态代理这个解决方案:不需要为每个类都创建一个代理类,只在需要使用代理的时候,通过反射机制动态地生成一个实现代理接口的匿名类的实例。代理的分类:动态代理和静态代理,即生成代理类的方式是什么。

动态代理的两种类型:JDKProxy 和 CGlib 两种,二者比对结果如下

类型原理特点JDKProxy运行时直接写Class字节码生成代理类效率高,反射执行效率低CodeGeneratorLibraryASM框架写 Class 字节码生成代理类效率低,FastClass 机制直接调用方法,执行效率高

Java 而言,ASM 就是字节码级别的编程,assembly ,即汇编语言。学过汇编的同学,有没有感觉很亲切呢?

JDKProxy。 JDK 是支持动态代理的,核心类为 Proxy

de65dea11801791bfe079cf83c67f2b2.png


JDK 的 Proxy 实现动态代理,优势是,抽象统一的 InvocationHandler 实现类,完成公共的代理增强动作。然后参数是 targetInstance 。不需要定义 Proxy 实现类,直接通过动态代理生成代理类实例即可。

测试 JDKProxy 。根据这个类图,来编写一个动态代理的测试类如下。
第一步,定义代理接口类:

public interface Delegate {void log();}

第二步,定义代理接口实现类:

public class DelegateImp implements Delegate{@Overridepublic void log() {System.out.println("Class is "+this.getClass().getName());}}

第三步,编写测试类:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Date;public class ProxyTest {public static void main(String[] args) {//这里定义的是如何对委托类进行访问DelegateImp imp = new DelegateImp();InvocationHandler handler = new InvocationHandler() {// proxy 这个类是最终的代理类// 自定义的 InvocationHandler 需要指定具体的 target 目标对象的@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用委托类的方法之前的操作System.out.println("Start to call "+method.getName()+",time is:"+new Date());//调用委托类的方法method.invoke(imp, args);//调用委托类之后的操作System.out.println("Finish to call "+method.getName()+",time is:"+new Date());return null;}};//创建一个代理类Delegate proxy = (Delegate)Proxy.newProxyInstance(DelegateImp.class.getClassLoader(), DelegateImp.class.getInterfaces(), handler);proxy.log();}}

运行结果:log 方法执行前后,多了一下增强动作。

Start to call log,time is:Mon Jan 20 10:59:54 CST 2020Class is javastudy.DelegateImpFinish to call log,time is:Mon Jan 20 10:59:54 CST 2020

装饰模式概述

装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。(来自百度百科的定义)

《Head first 设计模式》中描绘的该模式的静态结构图为:

93e4b792717f25b06902da73b730b5a0.png
  1. 具体组件类和装饰类必须实现相同的顶层接口 Component;
  2. 具体装饰实现类包含一个具体组件的引用,即装饰类的构造过程需要传入一个具体的组件类,以便对原组件类进行装饰;
  3. 装饰类可以对被装饰者的行为增强,在之前或之后加上自己的动作。

编程启示录

仔细分析了一下,发现代理模式和装饰模式的区别有两点:第一点,关联的类型不同。代理模式和装饰模式的区别,从类图结构上来看:

  • 代理关联的是具体的委托对象;装饰着装饰的是装饰者的接口类型;
  • 代理真正的委托对象,客户端是不知道的;装饰的具体对象,是由客户端来指定的。

第二点,目的不同。代理,着重是控制对委托对象的访问,由代理类本身决定谁是委托对象;装饰,是对被装饰对象的增强,由客户端指定对谁进行装饰。

另外,JDKProxy 动态代理的测试过程中,笔者想到的一些内容是:

JDKProxy 动态代理的核心是 InvokationHandler 的实现,它定义了如何对委托对象进行访问。如果在实际开发中,增强操作可以复用的话,这个接口的实现类并不会很多。但是,如果每个委托对象,都有自己的行为访问控制方式的话,那就跟静态代理没有什么区别了,因为需要为每个委托对象都创建一种 InvokationHandler 的实现类。
当然,就日常开发而言, InvokationHandler 基本上能够复用,实现类的数量不会太多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值