十三、代理模式
13.1 代理的概述
-
代理模式的作用
为其他对象提供一种代理以控制对目标对象的访问。某些情况下客户不想或不能直接引用另一个对象,而代理对象可在客户端和目标对象间起到中介作用。
-
代理模式一般涉及到的角色
-
抽象角色:真实对象和代理对象的共同接口;
-
真实角色:真实对象,最终要引用的对象;
-
代理角色:
- 内部含有对真实对象的引用,从而可以操作真实对象;
- 提供与真实对象相同的接口以便在任何时刻代替真实对象;
- 可在执行真实对象操作前后附加其他操作,相当于对真实对象进行封装。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FyIek5J9-1616892929242)(C:\Users\wang’bo’shi\AppData\Roaming\Typora\typora-user-images\image-20210325100832068.png)]
小贴士:
必须明确一个动态代理类可适用多个抽象角色和真实角色!
-
代理模式的分类
-
## (1).静态代理
优点:不需要修改目标对象就实现了功能的增加。
缺点:真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。如果事先并不知道真实角色则无法使用;
一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀。
静态代理的是演示:
-
抽象角色
/** * 抽象角色(USB接口) */ public interface USB { /** * 启动功能 */ void start(); /** * 工作 */ void service(); /** * 测试电脑CPU当前温度 */ int hotSize(); }
-
真实角色
/** * 真实角色(键盘实现类) */ public class KeyBord implements USB { @Override public void start() { System.out.println("键盘正在插入电脑中……"); } @Override public void service() { System.out.println("键盘正在工作中……"); } @Override public int hotSize() { return 50; } }
-
代理角色
/** * 静态代理角色(同真实角色实现类要实现USB接口)
/
public class UsbProxy implements USB {
/*
* 真实角色
*/
KeyBord keyBord = new KeyBord();
@Override
public void start() {
System.out.println("日志:调用start函数前置通知!");
keyBord.start();
System.out.println("日志:调用start函数后置通知!");
}
@Override
public void service() {
System.out.println("日志:调用service函数前置通知!");
keyBord.service();
System.out.println("日志:调用service函数前置通知!");
}
@Override
public int hotSize() {
System.out.println("日志:正在检测电脑温度中……");
int i = keyBord.hotSize();
if(i>=70){
System.out.println("电脑温度过高!");
return 0;
}
System.out.println("电脑温度正常!");
return 1;
}
}
4. 测试类
```java
public class Test {
public static void main(String[] args) {
UsbProxy usbProxy = new UsbProxy();
usbProxy.start();
System.out.println("-------------------");
usbProxy.service();
System.out.println("-------------------");
System.out.println("CPU当前温度:" + usbProxy.hotSize() + "摄氏度!");
}
}
运行结果:
/**
* 日志:调用start函数前置通知!
* 键盘正在插入电脑中……
* 日志:调用start函数后置通知!
* -------------------
* 日志:调用service函数前置通知!
* 键盘正在工作中……
* 日志:调用service函数前置通知!
* -------------------
* 日志:正在检测电脑温度中……
* 电脑温度正常!
* CPU当前温度:50摄氏度!
*/
- ## (2).动态代理
-
Java动态代理类位于java.lang.reflect包下,主要涉及到两个类:InvocationHandler接口和
Proxy类;
-
InvocationHandler接口仅定义了一个方法:
public object invoke(Object obj,Method method, Object[] args){
//obj一般是指代理类
//method是被代理的方法
//args为该方法的参数数组
//这个抽象方法在代理类中动态实现
}
- Proxy类即为动态代理类,主要方法包括:
protected Proxy(InvocationHandler h){
//构造函数,用于给内部的h赋值
}
static Object newProxyInstance(ClassLoader loader, Class[ ] interfaces, InvocationHandler h) {
//返回代理类的一个实例
//loader是类装载器
//interfaces是真实类所拥有的全部接口的数组
}
static Class getProxyClass (ClassLoader loader, Class[] interfaces) {
//获得一个代理类
}
动态代理的演示:
- 创建一个实现接口InvocationHandler的类;
- 在invoke方法内通过反射调用真实对象的方法,并添加附加操作;
- 创建被代理的类以及接口;
- 通过Proxy类的newProxyInstance() 创建一个代理;
- 必须传入一个InvocationHandler对象;
- 通过代理调用方法。
-
抽象角色
/** * 抽象角色 */ public interface USB { /** * 启动功能 */ void start(); /** * 工作 */ void service(); /** * 测试电脑CPU当前温度 */ int hotSize(); int lenth(int num); }
-
真实角色
/** * 真实角色 */ public class Mouse implements USB { @Override public void start() { System.out.println("鼠标正在插入电脑中……"); } @Override public void service() { System.out.println("鼠标正在工作中……"); } @Override public int hotSize() { System.out.println("鼠标温度"); return 50; } @Override public int lenth(int num) { return num; } }
-
动态代理角色—
注意!!!(此类不是动态代理类)
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; /** * 动态代理角色(此类不是动态代理类,getProxy()方法返回中的newProxyInstance()才是动态代理对象,运行期间动态生成) */ public class LogHandler implements InvocationHandler { /** * 要代理的真实角色(未知) */ Object target; public LogHandler(){ } /** * 要传入的真实角色 * @param target */ public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标对象:" + target.getClass()); System.out.println("目标对象-方法:" + method.getName()); System.out.println("目标对象-参数:" + Arrays.toString(args)); Object result = method.invoke(target,args); System.out.println("目标对象返回结果:" + result); return result; } /** * 获取动态代理的方法(JDK内部帮我们获取目标对象的各种信息,并负责自动调用……) * getClass().getClassLoader()---类加载器 * getClassLoader(),getClass().getInterfaces()---类实现的接口 * this---指的是执行该getProxy()方法时,加载本代理类中的invoke()方法 * @return */ public Object getProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } }
-
测试类
public class Test { public static void main(String[] args) { Mouse mouse = new Mouse(); LogHandler logHandler = new LogHandler(mouse); USB usb = (USB)logHandler.getProxy(); usb.start(); usb.lenth(11111); } 运行结果: /** * 目标对象:class com.wbs.proxy2.Mouse * 目标对象-方法:start * 目标对象-参数:null * 鼠标正在插入电脑中…… * 目标对象返回结果:null * 目标对象:class com.wbs.proxy2.Mouse * 目标对象-方法:lenth * 目标对象-参数:[11111] * 目标对象返回结果:11111 */ }
小贴士:
LogHandler类不是动态代理类!!
newProxyInstance()方法返回的才是动态代理对象,是在运行时动态创建的!
13.2 两种代理模式的区别
-
静态代理类确实存在,动态代理类在运行期动态生成
-
一个真实角色必须对应一个静态代理角色,而动态代理大大减少了代理类的数量(一个动态代理对象多个真是角色)
-
动态代理类不会作实质性的工作,在生成它的实例时必须提供一个handler,由它接管实际的工作(会自动执行handler的invoke方法)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/189507.html