代理模式
代理模式思想非常简单,为其他对象提供一种代理以控制对这个对象的访问。下面我举一个漫威中的英雄“钢铁侠”的例子,在战斗中钢铁侠的外盔甲帮托尼打架。
UML图
代码
- 接口,我这里举例的是漫威公司
interface Marvel{
void fly();
void guard();
void shooting();
}
- 托尼,本来是平凡人,因为继承了漫威的接口,然后有了钢铁外壳,称为了钢铁侠
class Musk implements Marvel{
@Override
public void fly() {
System.out.println("控制机器");
}
@Override
public void guard() {
System.out.println("控制机器");
}
@Override
public void shooting() {
System.out.println("控制机器");
}
}
- 钢铁侠的外壳
class IronMan implements Marvel{
private Marvel marvel;
public IronMan(Marvel marvel){
this.marvel = marvel;
}
@Override
public void fly() {
marvel.fly();
System.out.println("钢铁侠飞起来了");
}
@Override
public void guard() {
marvel.guard();
System.out.println("钢铁侠抵御了共计");
}
@Override
public void shooting() {
marvel.shooting();
System.out.println("钢铁侠向敌人做了射击!!");
}
}
- main方法中调用吧!
public static void main(String[] args) {
Marvel marvel = new IronMan(new Musk());
marvel.fly();
marvel.guard();
marvel.shooting();
}
应用场景
远程代理
以前我们2个项目之间希望有业务交流,就可以是使用webservice技术,而webservice就是远程代理。这样可以为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象在不同地址空间。
虚拟代理
如果创建一个对象需要花费很长的时间,我们可以使用代理模式,先创建一个代理对象,系统可以立即返回,而后台我们采用异步的方式创建真实的的对象,比如Android中,我们可以使用代理模式去异步加载图片。
安全代理
我们可以通过调用代理模式,而非真实对象,从而对访问者做权限验证
智能代理
比如我们需要统计一个类被调用的次数,我们可以直接调用代理类,然后再代理类中做调用统计。
总结
例子可能不是非常恰当,但思想没问题,代理模式也很简单,他可以在不改变原来逻辑代码的情况下,为对象添加新的功能,满足设计模式的“开放 - 封闭”原则,另外今天主要讲的是动态代理。
动态代理
动态代理使用很简单,原理方面本打算细说,但原理涉及到反射相关的知识,由于篇幅过长就不深入讲解了,如果以后有空,我会单独写一篇关于动态代理原理方面的博客,下面,我先抛出一个问题,再使用动态代理解决。
抛出问题思考
下面有3个类,分别是你好、再见、寒暄,
此时,我希望在每次say()方法调用的前面加上加上“打开麦克风”、在调用完say()方法的后面加上“关闭麦克风”。而nothing()方法就什么也不做。
interface SayInterface {
void say();
void nothing();
}
class Hello implements SayInterface {
@Override
public void say() {
System.out.println("Hello bridge!");
}
@Override
public void nothing() {
System.out.println("Hello Nothing");
}
}
class ByeBye implements SayInterface {
@Override
public void say() {
System.out.println("ByeBye Bridge");
}
@Override
public void nothing() {
System.out.println("ByeBye Nothing");
}
}
class Ask implements SayInterface {
@Override
public void say() {
System.out.println("How are you!");
}
@Override
public void nothing() {
System.out.println("Ask Nothing");
}
}
- 调用的方法如下,ProxyXXXX表示能创建你需要的代理类的工具
Hello hello = new Hello();
SayInterface proxySay = (SayInterface) ProxyXXXX.createProxy(hello);//此时我希望创建一个代理类
proxySay.say();
proxySay.nothing();
此时,你可以思考1分钟,如果不使用代理模式,你应该怎样完成ProxyXXXX类
动态代理解决
根据上面的问题,你是否发现,你需要写3个代理类,而且3个代理类的方法都非常相识,如果我们将3个代理类,换成100个类,你将写100个,维护将痛苦不堪……
所以,我们希望写一个能代理各种类的代理类,前提是被代理的类的需要的代理服务都一样。好吧,下面看看动态代理是什么样子吧!
- 下面是能创建代理类的Hander
class ProxyHandler implements InvocationHandler {
private Object target;
/*
这里就可以返回你需要的代理类
*/
public Object createProxy(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("say")){
System.out.println("打开麦克风");
method.invoke(target, args);
System.out.println("关闭麦克风");
} else {
method.invoke(target, args);
}
return null;
}
}
- 代码调用如下:
Hello hello = new Hello();
ProxyHandler handler = new ProxyHandler();
SayInterface proxySay = (SayInterface) handler.createProxy(hello);//此时我希望你能创建一个Hello的代理类
proxySay.say();
proxySay.nothing();
- 打印如下
打开麦克风
Hello bridge!
关闭麦克风
Hello Nothing
是不是如此神奇的事情就发生了,到底ProxyHandler是什么,为啥这么强大,因为它借助了java的反射功能。下面我们就简单介绍一下ProxyHandler吧!
理解ProxyHandler
- ProxyHandler中神奇的就是createProxy方法了,而createProxy其实就下面这个代码
Proxy.newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- 它根据ClassLoader和接口,就能创建一个代理类,而这个代理的每个方法的具体实现,还得借助于InvocationHandler接口。InvocationHandler接口是由一个抽象方法,如下:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
- invoke就是反射中对方法的实现,所以,你在main方法中,每调用一次代理类的方法,其实都是调用的invoke(),所以,代理的业务逻辑都再invoke()方法中。