代理模式应用场景十分广泛,随便一个框架都会用到,因此学好代理模式对后续框架学习是最基本的要素!!今天我们就来讲讲代理模式

目录

  • 1、简介
    • 1. 核心作用
    • 2. 角色分析
    • 2. 应用场景
    • 4. 分类
  • 2、静态代理
    • 1. 案例:房东租房
    • 2. 优劣分析
    • 3. 加深理解
  • 3、动态代理
    • 1. 简介
    • 2. Proxy 类
    • 3. InvocationHandler 接口
    • 4. 代码示例
    • 好处

首先,了解以下23种设计模式中 代理模式的定位,它是 结构性模式

1、简介

Proxy pattern

1. 核心作用

  • 通过代理,控制对对象的访问

    可以详细的访问某个(某类)对象的实现,在调用这个方法前做前置处理,调用这个方法后做后置处理(AOP的微观实现)

  • 代理模式是SpringAOP的核心实现机制!


2. 角色分析

抽象角色

  • 定义代理角色和真实角色的公共对外方法,一般会使用接口或者抽象类来解决

真实角色

  • 实现抽象角色,定义真实角色要实现的业务,供代理角色调用

代理角色

  • 实现抽象角色,代理真实角色,通过真实角色的业务来实现抽象方法,一般会有附属的业务

客户

  • 访问代理角色的人

2. 应用场景

安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。


4. 分类

  • 静态代理(静态定义代理类)
  • 动态代理(动态生成代理类)
    • JDK自带的动态代理
    • javaassist字节码操作库实现
    • CGLIB
    • ASM(底层使用指令,可维护性较差)

2、静态代理

static proxy

1. 案例:房东租房

接下来以房东租房这件实例,来讲讲代理模式

房东租房,如果房东懒得管太多,这时候就需要一个中介,来帮助房东租房并打理一切事情,这时候租房者就不需要直接和房东打交道了,而是通过中介间接和房东打交道,中介就是中间者,代理了房东,且可以在租房前后附加其他操作,比如:签合同,看房子等

这时候对象上述的四个角色就有四个对象

  1. 抽象角色:租房业务
  2. 真实角色:房东
  3. 代理角色:中介,可能还有带客户看房子等业务
  4. 客户:租房者

接下来,我们通过代码还原上述四个角色

  1. 抽象角色:表示租房这个业务,用接口实现

    //租房
    public interface Rent {public void rent();
    }
    
  2. 真实角色:代表房东,实现租房业务接口

    //房东
    public class Host implements Rent{public void rent() {System.out.println("房东要出租房子了");}
    }
    
  3. 代理角色中介,实现租房业务接口

    因为代理了房东,所以私有属性是房东对象,除了租房子业务外,可能还有看房、签合同、收中介费等业务

    public class Proxy implements Rent {private Host host;public Proxy() {}public Proxy(Host host) {this.host = host;}//代理租房子public void rent() {seeHouse();host.rent();contract();fare();}//看房public void seeHouse() {System.out.println("中介带你看房");}//签合同public void contract() {System.out.println("租赁合同");}//收中介费public void fare() {System.out.println("收中介费");}
    }
    
  4. 客户租房者,访问中介

    public class Client {public static void main(String[] args) {//房东租房子Host host = new Host();//代理,中介帮房东租房子,并且有一些附属操作Proxy proxy = new Proxy(host);//不需要找房东,直接找中介租房即可proxy.rent();}
    }
    


2. 优劣分析

好处

  1. 职责清晰

    使真实角色更加的简单专一,不管具体的业务

    • 这里房东只用给中介费就行了,其他一切都交给中介来做,实现了业务分工
  2. 智能化

    客户只需访问代理角色,减少了直接访问真实角色带来的问题

    • 加入这里房东有很多房子,自己一个人可能管理不过来,这时候每个客户的体验可能会变差,会出现很多问题
  3. 高拓展性

    业务发展拓展的时候,方便集中管理

缺点

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低

3. 加深理解

可能上述例子过于简单,不能直观的感受到代理模式的好处,我们再举个例子加深理解

首先创建一个业务实现接口

npublic interface UserService {public void add();public void delete();public void update();public void query();
}

然后再来一个业务实现类

public class UserServiceImpl implements UserService {public void add() {System.out.println("增加一个用户");}public void delete() {System.out.println("删除一个用户");}public void update() {System.out.println("修改了一个用户");}public void query() {System.out.println("查询了一个用户");}
}

再来个测试类

public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();userService.add();userService.delete();userService.update();userService.query();}
}

如果此时,我们需要增加一个日志业务,需要打印每个方法的执行

  • 普通修改在业务实现类中的每个方法中都要修改
public class UserServiceImpl implements UserService {public void add() {System.out.println("使用了add方法");System.out.println("增加一个用户");}public void delete() {System.out.println("使用了delete方法");System.out.println("删除一个用户");}public void update() {System.out.println("使用了update方法");System.out.println("修改了一个用户");}public void query() {System.out.println("使用了query方法");System.out.println("查询了一个用户");}
}

业务很多的情况下,修改量十分大,这时候用代理模式就能很好的解决我们的问题

我们新建一个业务代理类,在业务实现类里只需增加一个方法就可以实现上述新增业务

public class UserServiceProxy implements UserService {private UserServiceImpl userService;public void setUserService(UserServiceImpl userService) {this.userService = userService;}public void add() {log("使用了add方法");userService.add();}public void delete() {log("使用了delete方法");userService.delete();}public void update() {log("使用了update方法");userService.update();}public void query() {log("使用了query方法");userService.query();}public void log(String msg) {System.out.println("使用了" + msg + "方法");}
}

然后修改测试类,进行测试

package demo2;public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy proxy = new UserServiceProxy();proxy.setUserService(userService);proxy.add();proxy.delete();proxy.update();proxy.query();}
}

由此可见

  • 当业务需要拓展的时候,代理模式充分的体现了其高拓展性
  • 业务很多的时候,代理模式也方便管理

3、动态代理

dynamic proxy

1. 简介

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 分类
    • JDK自带的动态代理
    • javaassist字节码操作库实现
    • CGLIB
    • ASM(底层使用指令,可维护性较差)

接下来我们讲述JDK自带的动态代理

需要了解:Proxy(代理)、InvocationHandler(调用处理程序)

2. Proxy 类

代理

  • 都是静态方法,直接通过类名调用
  • 作用:动态生成代理类和对象

所有方法

创建动态类的方法:【重要】

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

每次通过Proxy生成的代理类对象都要指定对应的处理器对象,就是第三个参数

三个参数

  • 类加载器,来定义代理类
  • 代理类实现的接口列表
  • 处理器接口对象

3. InvocationHandler 接口

处理器接口

  • 通过invoke方法实现对真实角色的访问(就是调用真实角色的方法)

唯一的一个方法

三个参数

  • proxy:代理类
  • method:正在调用的方法
  • args:方法中的参数,默认即可

4. 代码示例

这里还是以上述租房子为实例,我们用动态代理的方式实现

Rent接口(抽象角色) 和 Host类(真实角色)不变

  1. 定义一个处理器接口实现类,继承InvocationHandler

    其中的invoke方法实现对真实角色方法的调用,因此该类中有真实角色私有属性,为传参使用

    package demo3;import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;public class ProxyInvocationHandler implements InvocationHandler {//定义真实角色private Rent host;//真实角色set方法public void setHost(Rent host) {this.host = host;}/**生成代理类方法1. 类加载器,为当前类即可2. 代理类实现的接口3. 处理器接口对象**/public Object getProxy() {return Proxy.newProxyInstance(this.getClass().getClassLoader(),host.getClass().getInterfaces(), this);}//处理代理实例,并返回结果//方法在此调用public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用真实角色方法Object result = method.invoke(host, args);//附加方法seeHouse();contract();fare();return result;}//看房public void seeHouse() {System.out.println("中介带你看房");}//签合同public void contract() {System.out.println("租赁合同");}//收中介费public void fare() {System.out.println("收中介费");}
    }
  2. 测试类

    package demo3;public class Client {public static void main(String[] args) {//真实角色:房东Host host = new Host();//处理器接口对象ProxyInvocationHandler handler = new ProxyInvocationHandler();//设置要代理的真实角色handler.setHost(host);//动态生成代理类Rent proxy = (Rent) handler.getProxy();//调用方法proxy.rent();}
    }
    
  3. 结果


好处

  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

其他好处同静态代理

GOF23设计模式(结构型模式)代理模式~相关推荐

  1. 设计模式(结构型)之代理模式(Proxy Pattern)

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  2. Java设计模式之结构型:代理模式

    前言: 我们一般在租房子时会去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做:再比如我们打官司需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们 ...

  3. 每天学习一个设计模式(七):结构型之代理模式

    目录 一.基本概念 二.通俗解释 三.代理模式的分类 1.普通代理 2.强制代理 代理是有个性的 3.动态代理 一.基本概念 代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下 ...

  4. 设计模式 - 结构型 - 装饰者模式

    2019独角兽企业重金招聘Python工程师标准>>> 介绍 意图:动态地给一个对象添加一些额外的职责.就增加功能来说,装饰器模式相比继承更为灵活. 主要解决:一般的,我们为了扩展一 ...

  5. [设计模式-结构型]享元模式(Flyweight )

    概括 名称 Flyweight 结构 动机 运用共享技术有效地支持大量细粒度的对象. 适用性 一个应用程序使用了大量的对象. 完全由于使用大量的对象,造成很大的存储开销. 对象的大多数状态都可变为外部 ...

  6. 【设计模式·结构型】桥接模式Bridge Pattern

    目的 该模式用于分离抽象与实现,并且抽象与实现可以独立变化 应用场景 (1)希望抽象和实现之间没有固定的绑定关系,不同抽象接口和实现可以组合和扩充,程序运行时动态选择.切换具体实现 (2)类层次结构, ...

  7. 设计模式(结构型)之享元模式(Flyweight Pattern)

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  8. Java设计模式之结构型:组合模式

    前言: 我们对于上面两幅图片肯定非常熟悉,这两幅图片我们都可以看做是一个文件结构,对于这样的结构我们称之为树形结构.在数据结构中我们知道可以通过调用某个方法来遍历整个树,当我们找到某个叶子节点后,就可 ...

  9. Java设计模式之结构型:外观模式

    一.什么是外观模式: 外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口.使用外观模式有以下几点好处: (1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要 ...

  10. Java设计模式之结构型:桥接模式

    一.什么是桥接模式: 桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯,桥接模式的作用就是为被分离的抽象部分和实现部分搭桥.在现实生活中一个物品在搭配不同的配件时会产生不同的动作和结果, ...

最新文章

  1. 程序员职业规划的3个锦囊
  2. angularjs 元素重复指定次数_5.2 设置循环次数:for +range 句式
  3. 安装Greenplum-perfmon-web监控软件遇到的问题及解决
  4. ArcMAP 用不同颜色区分地类
  5. Python帮助文档
  6. 数字栅格地图矢量化及三维显示教程
  7. thinkphp5前台index模板文件template配置
  8. 本机ip地址、本机DNS查询工具地址
  9. 「2019.7.22 考试」AC和WA0一步之遥
  10. 男生追女生时的21个致命问题
  11. JS实现图片大小自适应且位置居中,防止图片变形
  12. 天正建筑中如何将标注单位M改为mm
  13. Vue自定义组件之时间跨度选择器
  14. iOS开发之利用苹果系统自带地图进行地图开发
  15. Boosting方法入门
  16. 【《深度学习入门》—— 学习笔记(一)】
  17. 懒惰的苏珊 UVa1620
  18. 使用JavaWeb实现多多自走棋羁绊生成
  19. 华为C语言笔试题集合
  20. JAVA财务保证金管理模块开发-王大师王文峰开发(项目现场驻场开发)

热门文章

  1. 2022-2028年中国社区体育产业深度调研及投资前景预测报告
  2. bert速度提升fastbert
  3. MindSpore特性支持类
  4. 代码生成codegen
  5. 关键任务应用程序依赖于故障保护存储器
  6. 边缘的人工智能可以满足许多需求
  7. YOLO v1到YOLO v4(上)
  8. 2021年大数据常用语言Scala(十五):基础语法学习 元组  重点掌握
  9. PHP7.3中fileinfo怎么安装与开启
  10. SVN无法CO检出web目录