代理模式是很常见的一种设计模式,如AppCompatActivity兼容方案,Java中代理模式分为静态代理和动态代理,动态代理是JVM帮助我们实现的
一、代理模式
1.代理模式场景
有一名员工A,他出于某些原因需要公司签字,老板和秘书都可以执行公司签字的职能,但是秘书没有直接签字的权力,真正签字的必须是老板,而员工并不能直接找老板签字,只能和秘书打交道。由此看出,秘书只是一个代理者,他和老板拥有相同的职能,但是最终执行职能的还是老板,是员工和老板中间的窗口
![](https://i-blog.csdnimg.cn/blog_migrate/4a40cd7ae130b7696c33efe80caa003e.png)
2.将上面的场景转化为代码
职能接口:
package delegate;
public interface Function {
void sign();
}
老板:
package delegate;
class Boss implements Function {
@Override
public void sign() {
System.out.println("老板开始签字");
}
}
秘书:
package delegate;
public class Secretary implements Function {
private final Boss boss;
public Secretary() {
this.boss = new Boss();
}
@Override
public void sign() {
System.out.println("秘书交由老板签名");
boss.sign();
}
}
员工:
package delegate.other;
import delegate.Secretary;
public class Employee {
public static void main(String[] args) {
Secretary secretary = new Secretary();
System.out.println("请求签名");
secretary.sign();
}
}
结果:
请求签名
秘书交由老板签名
老板开始签字
3.代理模式条件
根据上面的代码,我们可以发现,代理模式有两个条件:
- 代理类和被代理类必须有同一个父类或接口
- 代理对象持有被代理对象
二、虚代理
kotlin中我们常常使用懒加载,只有在对象用到时,才实例化创建它,虚代理就是这种模式
1.场景
老板很忙,不一定一直都在公司,现在秘书也可以签名了,但是老板在的时候,还是优先老板签名。公司职能新增了开会,开会必须要等待老板在场
![](https://i-blog.csdnimg.cn/blog_migrate/0d96f50869466bceb6bc8cbe1d487935.png)
2.代码
职能接口:
package delegate;
public interface Function {
void sign();
void meeting();
}
老板:
package delegate;
class Boss implements Function {
@Override
public void sign() {
System.out.println("老板开始签字");
}
@Override
public void meeting() {
System.out.println("老板开始开会");
}
}
秘书:
package delegate;
public class Secretary implements Function {
private volatile Boss boss;
@Override
public void sign() {
if (boss != null) {
System.out.println("秘书交由老板签名");
boss.sign();
} else {
System.out.println("秘书开始签名");
}
}
@Override
public void meeting() {
waitBoss();
boss.meeting();
}
public void waitBoss() {
if (boss == null) {
synchronized (this) {
if (boss == null) {
System.out.println("等待老板回公司");
boss = new Boss();
}
}
}
}
}
员工:
package delegate.other;
import delegate.Secretary;
public class Employee {
public static void main(String[] args) {
Secretary secretary = new Secretary();
System.out.println("请求签名");
secretary.sign();
System.out.println("\n请求开会");
secretary.meeting();
System.out.println("\n请求签名");
secretary.sign();
}
}
结果:
请求签名
秘书开始签名
请求开会
等待老板回公司
老板开始开会
请求签名
秘书交由老板签名
老板开始签字
三、保护代理
保护代理在对象访问时进行权限检查
1.场景
老板的老婆可以问公司的效益,但员工不能问
![](https://i-blog.csdnimg.cn/blog_migrate/d6dac53c8f1f5ae2fd5817f2983ee9a2.png)
2.代码
职能接口:
package delegate;
public interface Function {
void sign();
void meeting();
void report(String who);
}
老板:
package delegate;
class Boss implements Function {
@Override
public void sign() {
System.out.println("老板开始签字");
}
@Override
public void meeting() {
System.out.println("老板开始开会");
}
@Override
public void report(String who) {
System.out.println("老板开始给" + who + "打报告");
}
}
秘书:
package delegate;
public class Secretary implements Function {
private volatile Boss boss;
@Override
public void sign() {
if (boss != null) {
System.out.println("秘书交由老板签名");
boss.sign();
} else {
System.out.println("秘书开始签名");
}
}
@Override
public void meeting() {
waitBoss();
boss.meeting();
}
@Override
public void report(String who) {
if (who == null) return;
if (who.equals("老婆")) {
waitBoss();
boss.report(who);
} else {
System.out.println(who + "被开除了");
}
}
public void waitBoss() {
if (boss == null) {
synchronized (this) {
if (boss == null) {
System.out.println("等待老板回公司");
boss = new Boss();
}
}
}
}
}
员工:
package delegate.other;
import delegate.Secretary;
public class Employee {
public static void main(String[] args) {
Secretary secretary = new Secretary();
System.out.println("老婆请求报告");
secretary.report("老婆");
System.out.println("\n张三请求报告");
secretary.report("张三");
}
}
结果:
老婆请求报告
等待老板回公司
老板开始给老婆打报告
张三请求报告
张三被开除了
四、动态代理
以上我们都是使用了静态代理,每次接口新增方法,那么其实现类都需要改动,JVM提供了动态代理的方式
1.创建动态代理Handler
package dynamicdelegate;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicInvocationHandler implements InvocationHandler {
private Function boss;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("report")) {
if (args[0] == null) {
return null;
}
if (args[0].equals("老婆")) {
return method.invoke(boss, args);
} else {
System.out.println(args[0] + "被开除了");
return null;
}
}
return method.invoke(boss, args);
}
/**
* 设置被代理对象
*
* @param boss
*/
public void setTarget(Function boss) {
this.boss = boss;
}
}
员工:
package dynamicdelegate.other;
import dynamicdelegate.Boss;
import dynamicdelegate.DynamicInvocationHandler;
import dynamicdelegate.Function;
import java.lang.reflect.Proxy;
public class Employee {
public static void main(String[] args) {
DynamicInvocationHandler handler = new DynamicInvocationHandler();
Boss boss = new Boss();
handler.setTarget(boss);
Function proxy = (Function) Proxy.newProxyInstance(
boss.getClass().getClassLoader(),
boss.getClass().getInterfaces(),
handler);
proxy.report("老婆");
proxy.report("张三");
}
}
结果:
老板开始给老婆打报告
张三被开除了
2.动态代理原理
动态代理实际上是生成class字节码,根据InvocationHandler的invoke方法中业务逻辑,在Boss类中每个方法都相应的添加了业务逻辑后,生成了一个新的类