Java设计模式之代理模式
创始人
2024-01-22 06:00:41
0

目录

1.概述

2. 静态代理模式

2.1基于接口的静态代理

2.2基于继承的静态代理

2.3优缺点

3.动态代理模式

3.1JDK 动态代理

3.2 CGlib 动态代理

3.3优缺点

1.概述

-    代理模式指: 为一个对象提供一个替身,以控制对这个对象的访问。既通过代理对象访问目标对象,这样做的好处是: 可以在目标对象实现的基础上,增加额外的功能操作,即扩展目标对象的功能

- 代理模式分为: 静态代理模式和动态代理模式(JDK 和CGLIB)。

2. 静态代理模式

- 概述:  静态代理由开发者对抽象主题编写相关代理类实现,编译之后生成代理类的class.

- 使用: 静态代理在使用时,需要定义接口或者父类, 目标对象与代理对象一起实现接口或者继承共同的父类。

 - 实例: 以外卖骑手为例,骑手代理顾客执行购买,等待,取餐的操作       

2.1基于接口的静态代理

- Foodie 品尝接口(抽象主题)

/*** 美食家---> 抽象主题: 静态代理*/
public interface Foodie {/*** 品尝美食*/void eat();
}

- RealFoodie 真实品尝类(真实主题)

/*** 真实美食家---> 真实主题: 静态代理*/
public class RealFoodie implements  Foodie{@Overridepublic void eat() {System.out.println("开始品尝美食....");}
}

- ProxyFactory 代理工厂

/*** 重写Foodie接口的方法*/@Overridepublic void eat() {//增加扩展功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始配送");//调用目标对象方法foodie.eat();}

-  Test 测试类

public class Test {public static void main(String[] args) {//1.静态代理---> 基于接口RealFoodie realFoodie=new RealFoodie();//填入目标对象Foodie foodie=new ProxyFactory(realFoodie);foodie.eat();}
}

- 输出结果

开始购买....
开始等待....
开始配送....
开始品尝....

总结 : 以上代码可以看出: ProxyFactory代理工厂替目标对象扩展了骑手配送的功能。目标对象没有作任何更改,因此目标对象和扩展功能互不影响,职责分明。

注意 : 目标对象和代理工厂都要实现抽象主题, 这是基于接口的一种方式。

2.2基于继承的静态代理

 - 使用场景: 在代理工厂不想实现接口去扩展功能时,就可以使用继承的方式(即继承和真实主题共有的父类或直接继承真实主题)。

- Foodie 抽象主题(和上面一样没做任何改动)

- RealFoodie 真实主题(和上面一样没做任何改动)

- ProxyFactory 代理工厂

/*** 代理工厂直接继承真实主题--->即目标对象*/
public class ProxyFactory extends  RealFoodie{/*** 重写父类的方法*/@Overridepublic void eat() {//扩展功能System.out.println("开始购买....");System.out.println("开始等待....");System.out.println("开始配送....");//调用父类(即目标对象)的方法super.eat();}
}

2.3优缺点

优点:

-    可以在不修改目标对象的前提下,能通过代理对象对目标功能进行扩展。

-    目标对象和代理的扩展功能职责清晰不会产生耦合。

缺点:

-   因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。

-   一旦接口增加方法,目标对象与代理对象都要维护。

3.动态代理模式

- 概述: 动态代理是在运行时动态生成的,通过反射动态生成代理类字节码。

- 分类: 动态代理模式可分为JDK动态代理(基于接口),CGlib(继承方式)。

3.1JDK 动态代理

- 实现:目标对象实现抽象接口,代理方法逻辑类实现InvocationHandler调用处理器接口。

- Foodie 抽象主题 

/*** 美食家--->抽象主题: JDK动态代理*/
public interface Foodie{void eat();
}

- RealFoodie 真实主题

/*** 真实主题---> JDK动态代理*/
public class RealFoodie implements  Foodie{/*** 品尝美食*/@Overridepublic void eat() {System.out.println("开始品尝....");}
}

- MethodInvocationHandler 方法逻辑调用处理类

  该类用于处理代理方法逻辑及或利用反射创建代理对象:

/*** 实现代理方法逻辑类----> JDK 动态代理*/
public class MethodInvocationHandler implements InvocationHandler {//定义未知目标对象private Object target;public MethodInvocationHandler(Object target) {this.target = target;}/** 创建代理工厂**/public Object getInstance(){/*** ClassLoader loader, 目标对象的类加载器* Class[] interfaces, 目标对象所实现的所有接口* InvocationHandler h  代理的方法逻辑自动调用重写的invoke*/return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MethodInvocationHandler(target));}/** 处理代理的方法逻辑*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//扩展新功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始送餐...");//调用目标对象的方法Object invoke = method.invoke(target, args);return invoke;}
}

- Test测试类

public class Test {public static void main(String[] args) {//创建真实主题RealFoodie realFoodie=new RealFoodie();//创建代理方法逻辑MethodInvocationHandler methodInvocationHandler=new MethodInvocationHandler(realFoodie);//创建代理对象--->填入目标对象Foodie foodie= (Foodie) new MethodInvocationHandler(realFoodie).getInstance();foodie.eat();}
}

3.2 CGlib 动态代理

- 前置操作: 引入CGlib的jar包。

- 使用场景:目标对象不想实现接口时,CGlib使用继承来实现

- 实现: 代理方法拦截类实现MethodInterceptor 即方法拦截接口。

- MethodInterceptor 代理方法拦截类

  该类用于创建代理对象并处理代理方法逻辑(对目标对象方法进行拦截) :

/*** 代理方法拦截类---> CGlib动态代理*/
public class MethodInterceptor implements net.sf.cglib.proxy.MethodInterceptor {//目标对象private  Object target;public MethodInterceptor(Object target) {this.target = target;}/*** 创建代理对象*/public Object createInstance(){//1.设置工具类Enhancer enhancer=new Enhancer();//2.设置父类enhancer.setSuperclass(target.getClass());//3.设置回调函数enhancer.setCallback(this);//4.创建代理对象Object o = enhancer.create();return  o;}/*** 写入拦截扩展代码* @param o 目标对象* @param method 所扩展目标对象的方法* @param objects 方法参数* @param methodProxy 代理对象* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//扩展功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始送餐...");//调用父类指定方法(拦截目标对象的方法)Object invoke =methodProxy.invokeSuper(o,objects);return invoke;}
}

- RealFoodie 真实主题类

/*** 真实主题---->CGlib动态代理*/
public class RealFoodie {void eat(){System.out.println("开始品尝...");}
}

- Test测试类

public class Test {public static void main(String[] args) {//创建真实主题RealFoodie realFoodie = new RealFoodie();//创建代理方法拦截器并创建代理对象RealFoodie realFoodie1 = (RealFoodie) new MethodInterceptor(realFoodie).createInstance();realFoodie1.eat();}
}

3.3优缺点

优点:

- 如扩展功能类似时,代理工厂类对象是未知的,就可以使用一个代理对象完成扩展功能,使用时指定不同目标对象即可。

- 代理工厂无需实现抽象接口的方法,因为是利用反射在运行时创建的代理对象。

缺点:

- CGlib : 通过继承的方式进行代理,无法处理被final修饰类的情况。

- JDK: 只能基于接口处理

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...