引子
代理模式?代理是个什么意思,帮我干事,帮我做我不想做的。来,老哥,帮我取下外卖!快帮我打一会儿彩虹六号,我上个厕所!总而言之吧,代理就是找个人去帮你完成你像完成的事情。
官方定义:Proxy Pattern代理模式是一个使用率非常高的模式,为其他对象提供一种代理以控制对这个对象的访问。
来先看看类图:
抽象主题类
public interface R6GamePlayer {
void loginUbisoft(String account, String passwd);
void teamKill();
void clearCush();
}
真实主题类
public class BossPlayer implements R6GamePlayer {
private String name = "";
public BossPlayer(String name) {
this.name = name;
}
@Override
public void loginUbisoft(String account, String passwd) {
System.out.println("登录名为:" + account + "密码为:" + passwd);
}
@Override
public void teamKill() {
System.out.println("爆头队友,一爆一个准!");
}
@Override
public void clearCush() {
System.out.println("开包开包,开50包!墨冰必中!");
}
}
代理类
public class ProxyPlayer implements R6GamePlayer {
private R6GamePlayer r6GamePlayer = null;
public ProxyPlayer(R6GamePlayer r6GamePlayer) {
this.r6GamePlayer = r6GamePlayer;
}
@Override
public void loginUbisoft(String account, String passwd) {
this.r6GamePlayer.loginUbisoft(account, passwd);
}
@Override
public void teamKill() {
this.r6GamePlayer.teamKill();
}
@Override
public void clearCush() {
this.r6GamePlayer.clearCush();
}
//不光完成老板任务,还能帮忙杀个人质
public void killHostage() {
System.out.println("我,FUZE,人质杀手,^-^");
}
}
结果
public class Client {
public static void main(String[] args) {
R6GamePlayer r6GamePlayer = new BossPlayer("Fuze");
R6GamePlayer proxy = new ProxyPlayer(r6GamePlayer);
proxy.loginUbisoft("fuckUbi", "thanksUbi");
proxy.teamKill();
proxy.clearCush();
((ProxyPlayer) proxy).killHostage();
}
}
代理模式的优点
职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务。
高扩展性,具体主题角色是随时都会发生变化的,只要它实现了接口。
智能化。
代理模式的使用场景
SpringAOP,非常典型的动态代理实现。
代理模式的扩展
- 普通代理
- 强制代理
- 动态代理
动态代理
动态代理就是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。所以是代理的对象是可以动态的变化的。
动态代理类
public class R6PlayerIH implements InvocationHandler {
//被代理者
Class cls = null;
//被代理的实例
Object obj = null;
//我要代理谁
public R6PlayerIH(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
//如果是登录,要发送一个安全提醒
if (method.getName().equalsIgnoreCase("loginUbisoft")) {
System.out.println("老九号又被盗啦!!!");
}
return result;
}
}
动态代理的场景类
public class ClinetIH {
public static void main(String[] args) {
//定义一个痴迷R6的哈哈怪
BossPlayer player = new BossPlayer("老九");
//定义一个handler
InvocationHandler handler = new R6PlayerIH(player);
//开始打游戏,记下时间戳
System.out.println("开始时间是: 2019-4-16 10:00:00");
//获得类的class loader
ClassLoader cl = player.getClass().getClassLoader();
//动态产生一个代理人
R6GamePlayer proxy = (R6GamePlayer) Proxy.newProxyInstance(cl, new Class[]{R6GamePlayer.class}, handler);
//登录
proxy.loginUbisoft("DJgoooooo", "hahahahaha");
//杀队友
proxy.teamKill();
//开包
proxy.clearCush();
System.out.println("游戏结束时间:" + new Date());
}
}
结果
总结
动态代理实现步骤
- 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法;
- 2.创建被代理的类以及接口;
- 3.调用Proxy的静态方法,创建一个代理类:
- newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);
- 4.通过代理调用方法。
动态代理实现思路
实现功能:通过Proxy的newProxyInstance返回代理对象
- 声明一段源码(动态代理产生);
- 编译源码(JDK Compiler API),产生新的类(代理类);
- 将这个类load到内存当中,产生一个新的对象(代理对象);
- return 代理对象。