代理模式

二十三种经典的设计模式之一,属于一种结构模式。

二十三种设计模式不会单独开篇去讲,有时间会汇总写一篇文章去接单介绍二十三种模式,然后根据“创建模式”、“行为模式”、“结构模式”三种类型去对比二十三中设计的优缺点,喜欢我的文章的小伙伴点个关注呗~

定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介左右。

优点

  • 职责清晰,真实的角色就是实现实际的业务逻辑,不用关系其他非本职责的食物,通过后期的代理完成一件事物,附带的结果就是编程简洁清晰。
  • 代理对象可以在客户端和目标之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
  • 高扩展性

模式结构

一个真正的你要访问的对象(目标类),一个代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。

代理模式分为静态代理和动态代理。

静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是程序运行之前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

动态代理是在现实阶段不用关心代理类,而在运行阶段才指定哪一个对象。

静态代理

刚刚我们说了,静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现共同接口或者继承相同父类。
其实说白了就是为了控制对象引用,生活场景中,我们以买车为例,如果我们要买一辆车必须通过汽车4S 店,汽车4S 店就是充当代理角色,其目的是物流控制买车客户的买车行为,必须通过汽车4S 店才能从骑车厂商买一辆车。

1.首先买车是一种行为,客户和代理厂商都需要实现的接口

public interface IBuyCar{void buyCar();
}复制代码

2.声明一个要买车的客户,实现买车的接口

public class Customer implement IBuyCar{public int cash;//预算买车款public String name;//名字public Customer(int cash,String name){this.cash = cash;this.name = name}@Overridepublic void buyCar(){System.out.println(name+"买了一辆车花了"+cash);}}复制代码

3.声明一个买车代理骑车4S 店,同样实现买车接口,必须接受客户下单。

public class PorscheProxy implement IBuyCar{public Customer customer;//public PorscheProxy(Customer customer){this.customer = customer;}@Overridepublic void buyCar(){customer.buyCar();}}复制代码

4.创建一个客户端,模拟一次买车

public static void main(String[]args){Customer c = new Customer(10000,"ZhangSan");PorscheProxy proxy = new PorscheProxy(customer);proxy.buyCar();
}复制代码

OK,成功的使用代理模式完成了一次购车操作。

有什么用?

然后,可能有同学会问了,你这个代码优在那里?难道客户就不能自己去买车么?当然可以,如果在使用场景中实现类能满足要求时,我们当然可以直接实现类,但当实现类不能满足要求,要扩展需求,根据开闭原则,你又不能修改实现类代码,这时你就用代理类。比如买车的时候,需要对客户进行一个购车款审核,如果符合条件就买,不符合就不能买。

@Override
public void buyCar() {//实现为客户买车if(customer.cash < 1000000){System.out.println("buyCar","你的钱不够买一辆Porsche,建议去看看大众");return;}customer.buyCar();
}复制代码

优缺点

  • 优点:可以做到在不修改目标对象的功能的前提下,对目标功能扩展
  • 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。

如何解决静态代理中的缺点呢?答案是动态代理。

动态代理

刚刚我们讲的都是静态代理,所谓的静态代理,就是自己要为要代理的类写一个代理类,或者用工具为其生成的代理类,总之,就是程序运行前就已经存在的编译好的代理类,这样有时会觉得非常麻烦,也导致非常不灵活,相比静态代理,动态带来具有更强的灵活性,因为它不用我们在设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延时到程序运行时由JVM 来实现。

还是刚刚那个买车的例子

public class Client {public static void main(String[]args){IBuyCar customer = (IBuyCar)Proxy.newProxyInstance(IBuyCar.class.getClassLoader(), IBuyCar.class.getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在转调具体目标对象之前,可以执行一些功能处理//转调具体目标对象的方法Object invoke = method.invoke(this, args);//在转调具体目标对象之后,可以执行一些功能处理return invoke;}});customer.buyCar();}
}复制代码

以上,就是动态代理的写法
可能有同学会这样写好像不太符合我们的需求,我怎么根据客户的现金数去判断能否买车呢?
我是这样理解的,因为动态代理是为了解决灵活性,所以一般不推荐强绑定业务对象,这里我们一般用于解决某些具有共性的场景,我们可以在代理方法调用前后分别干一些想干的事情。如果一定要强绑定业务,那么推荐使用静态代理哦。
当然,可能会有同学要钻牛角尖,我就要用动态代理实现买车的需求,且控制金额。这里我还是写一下代码实现吧,我不推荐这种做法哦,具体看业务逻辑吧~

直接贴代码吧,创建了DynamicProxy 类继承了InvocationHandler,然后在invoke 方法里面判断就好。

优缺点

  • 优点

    • 减少编程的工作量
    • 系统扩展性和可维护性增强
  • 缺点
    • 使用了反射,降低性能

扩展

再来两个小的扩展知识点吧~

CGLIB 代理

上面的静态代理和动态代理模式都是要求目标实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何接,这个时候就可以使用以目标对象子类的方式实现代理,这种方法叫做 cglib 代理。

cglib 代理又称子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

CGLIB(Code Generation Library)是一个开源项目!

  • JDK 的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用CGLIB 实现。
  • CGLIB 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 java 接口。它广泛的被许多 AOP的框架使用,例如 Spring。
  • CGLIB 包的底层是通过使用一个小而快的字节码处理框架 ASM 来转换字节码生成新的类。不鼓励直接使用 ASM,因为它要求你必须对 JVM 内部结构包括 class 文件的格式和指令集都很熟悉。

好了,没看懂 CGLIB 的实现原理没关系。我们只是简单了解一下,下面还是以买车的例子来讲解。

首先,运行时通过 ASM 来生成一个代理类 CGLIBProxy,继承子 Customer,然后重写对应的方法,看代码。

public class CGLIBProxy extends Customer{@Overridepublic void buyCar(){//在转调具体目标对象之前,可以执行一些功能处理//转调具体目标对象的方法super.buyCar();  //在转调具体目标对象之后,可以执行一些功能处理}}复制代码

以上,大概就是酱紫吧。在 Android 开发中好像没用到这玩意,我们知道这回事就行了哈。

Retrofit 中的代理模式

之所以单独写代理模式,主要是因为他喵的二十三种设计模式,就代理没看懂,以至于我每次在研究 Retrofit 源码的时候,看到代理全程懵逼。

不多说了,直接看 Retrofit.create()方法

public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {private final Platform platform = Platform.get();@Override public Object invoke(Object proxy, Method method, Object... args)throws Throwable {// If the method is a method from Object then defer to normal invocation.if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}//加载处理API接口方法ServiceMethod serviceMethod = loadServiceMethod(method);//创建OkHttpCallOkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);//通过对应的CallAdapter适配自定义并期望返回的Callreturn serviceMethod.callAdapter.adapt(okHttpCall);}});复制代码

}

这里我们在调用Service 方法的时候,根据方法参数,创建了ServiceMethod。至于ServiceMethod是干嘛的,这里不作详细讲解了。

/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod<T> 复制代码

翻译:将接口方法的调用改编为HTTP调用

Java 基础(十九)代理相关推荐

  1. Java基础:动态代理

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 概述 在运行时,动态创建一组指定的接口的实现类对象(代理对象)! 代理是实现AOP(面向切面编程)的核 ...

  2. Python基础十九:多进程

    Python基础十九:多进程 Python基础系列内容为学习廖雪峰老师Python3教程的记录,廖雪峰老师官网地址:廖雪峰Python3教程 Author:yooongchun Email:yooon ...

  3. java第十九次学习笔记

    java第十九次学习笔记 异常 java第十九次学习笔记 前言 一.try catch 二.多个异常如何处理 前言 斯人若彩虹遇上方知有 一.try catch package Demo01;impo ...

  4. 学习spring必须java基础知识-动态代理

    2019独角兽企业重金招聘Python工程师标准>>> Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Jav ...

  5. java基础(十) 深入理解数组类型

    戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 1. 数组类简介   在java中,数组也是一种引用类型,即是一种类. ...

  6. java参数注解pam_吃透Java基础十:注解

    一.什么是注解 官方定义: 注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分.注解对于代码的运行效果没有直接影响. 注解有许多用处,主要如下: 提供信息给编译器: ...

  7. Java基础知识(九) 容器

    Java基础知识 1. Java Collections 框架是什么 2. 什么是迭代器 3. ArrayList.Vector 和 LinkedList 有什么区别 4. HashMap.Hasht ...

  8. Java基础之——动态代理

    动态代理 文章目录 动态代理 1.动态代理总括 1.1.★ 什么是动态代理 ? 1.2.★ 知道动态代理能做什么 ? 2.什么是代理? 3.★ 使用代理模式的作用 4.代理的分类 5.★代理类的功能 ...

  9. Java基础知识:代理

    一.代理的概念 动态代理技术是整个java技术中最重要的一个技术,它是学习java框架的基础,不会动态代理技术,那么在学习Spring这些框架时是学不明白的. 动态代理技术就是用来产生一个对象的代理对 ...

  10. Java基础-JDK动态代理

    JDK的动态代理依靠接口实现  代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. ...

最新文章

  1. Matlab Robotic Toolbox V9.10工具箱(三):轨迹规划
  2. php in_array 和 str_replace
  3. C语言之基本算法32—鞍点
  4. mockito单元测试示例_Mockito模拟示例
  5. 2、开关灯、选项卡、隔行换色
  6. 几款少儿编程软件介绍
  7. 企业搭建网站主要流程以及六个基本步骤
  8. 测试--插拔寿命测试
  9. 从控制台输入一个三位数,如果是水仙花数(是指一个三位数,其各位数字立方和等于该数 )就打印“是水仙花数”,否则打印“不是水仙花数”
  10. Android关闭屏幕,但不休眠
  11. 2021年CS保研经历(一):北邮CS夏令营、北师大AI夏令营、天津大学CS夏令营
  12. windows 文件在linux下运行显示no such file or directory
  13. 【06月04日】A股滚动市盈率PE历史新低排名
  14. 计算机毕业设计基于asp.net的幼儿园接送信息管理系统
  15. 计算机显卡驱动不起游戏,Win10玩游戏提示显卡驱动已停止响应怎么办? 重置显卡驱动的技巧...
  16. 桌面日历的手机APP
  17. 清华最新推荐的AI顶会和期刊,很有必要follow一下 | 资源图谱
  18. comsol流体仿真 ,流固耦合,圆管内流体驱动物块的移动和 流体驱动扇叶的转动
  19. python中range倒序输出
  20. 弘辽科技:直通车如何拉回精准人群

热门文章

  1. C#将数据库中的数据绑定到dataGridView
  2. php防止SQL注入
  3. uni-app 更改默认组件样式
  4. ELK logstash grok匹配失败存另外的es表
  5. mysql 标记_mysql-徽章/标记内容自用户上次看到以来已...
  6. 全网首发:JDK绘制文字:八、绘制函数简要分析
  7. 硬盘出错,导致文件坏了
  8. WORD中如何进行双行合一
  9. Migrate Project to Gradle? This project does not use the Gradle build system
  10. JAVA数组批量设值(初始化)的办法