赞
踩
Proxy(代理)模式是常见设计模式之一,“代理”顾名思义就是“替代”的意思,很容易理解。根据GoF(《Design Patterns: Elements of Reusable Object-Oriented Software》的四位作者)的代理设计模式意图是:Provide a surrogate or placeholder for another object to control access to it.就是说为另一个对象提供代理或占位符,以控制对其的访问。定义本身非常清晰,当我们要提供功能的受控访问时,将使用代理设计模式。
先举个例子:
比如你现在拥有一套多余的房子想卖掉,但是你不知道谁要买,你不可能在大街上见到一个人就问“兄弟要买房吗?”;我们肯定想到了卖房中介,是的,我们把我们房子的一些信息告诉中介公司然后让他帮我们卖,然后想买房的人肯定不会直接找到你而是去了中介公司,为啥?因为中介的房子多啊有的挑,况且想买房的人根本就不认识你。于是他通过中介公司心意你的房子然后买下。
分析:在上面这个例子中,要卖房子的是你,而执行的人确实中介公司,于是中介公司就充当了“代理”的身份,客户(买房子的人)就不需要直接跟你对接。
下面画一张UML图:
分析:我们定义了一个House接口里面有一个sale()方法,有两个实现类,一个是实体类(真实卖房子的人)RealManOfSaleHouse与代理类SaleHouseProxy,其中代理类SaleHouseProxy还有一个额外的宣传装修房子的方法decorate(),而且代理类保存一个引用使得代理可访问实体,这样代理就可以来代替实体来卖房。下面上代码:
House接口:
package com.proxy.learn;
/**
* Created on 2020/2/28
* Package com.proxy.learn
*
* @author dsy
*/
public interface House {
void sale();
}
RealManOfSaleHouse类:
package com.proxy.learn; /** * Created on 2020/2/28 * Package com.proxy.learn * * @author dsy */ public class RealManOfSaleHouse implements House { @Override public void sale() { System.out.println("售房啦,售房啦,130平米冬暖夏凉首付仅需20W,瞧一瞧看一看啦"); } }
SaleHouseProxy类:
package com.proxy.learn; /** * Created on 2020/2/28 * Package com.proxy.learn * * @author dsy */ public class SaleHouseProxy implements House{ private RealManOfSaleHouse owner ; public SaleHouseProxy(RealManOfSaleHouse owner){ this.owner = owner; } @Override public void sale() { owner.sale(); decorate(); } public void decorate(){ System.out.println("装修房子喽,专业设计师保你冬暖夏凉,24期免息,瞧一瞧看一看啦"); } }
测试类:
package com.proxy.learn; /** * Created on 2020/2/28 * Package com.proxy.learn * * @author dsy */ public class SaleHouseTest { public static void main(String[] args) { RealManOfSaleHouse owner = new RealManOfSaleHouse(); SaleHouseProxy proxy = new SaleHouseProxy(owner); proxy.sale(); } }
打印结果:
售房啦,售房啦,130平米冬暖夏凉首付仅需20W,瞧一瞧看一看啦
装修房子喽,专业设计师保你冬暖夏凉,24期免息,瞧一瞧看一看啦
以上就是一个静态代理的例子,在这里代理类对接口实现了扩展,加了一个decorate()方法,这表明静态代理有一个优点:可以进行一些功能的附加与增强。但也有缺点:
静态代理与动态代理有什么区别?从字面上看就是“静态”与“动态”的区别。以上面的例子来说,我们使用SaleHouseProxy proxy = new SaleHouseProxy(owner);这行代码手动new了一个代理对象然后调用业务方法,在动态代理中就不需要我们手动去写而是由Proxy.newProxyInstance()这个方法在程序运行时期来动态创建。
下面结合一个例子来说明:
我们模拟一个信息发送的过程:假设Bob要向Alice发送信息,Bob与Alice相隔千里,于是Bob打开了微信发送给Alice,见图:
我们先写一个核心业务接口IMessage类提供发送信息的功能
package com.dynamicProxy.learn;
/**
* Created on 2020/2/28
* Package com.dynamicProxy.learn
*
* @author dsy
*/
public interface IMessage {//核心业务接口
public void message(String message);
}
接口实现类MessageImpl :
package com.dynamicProxy.learn; /** * Created on 2020/2/28 * Package com.dynamicProxy.learn * * @author dsy */ public class MessageImpl implements IMessage { @Override public void message(String message) { System.out.println("发送内容:"+message); } }
以上两个和静态代理类中的代码没什么区别,接下来看代理类ServerProxy :
package com.dynamicProxy.learn; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created on 2020/2/28 * Package com.dynamicProxy.learn * * @author dsy */ public class ServerProxy implements InvocationHandler { private Object object; //核心业务对象 public Object bind(Object object){ //保存真实业务对象 this.object = object; //获取真实业务主题所在类对应的类加载器,因为需要分析真实业务主题接口中所拥有的方法,才可以构建动态子类 //所有的动态代理都是基于接口的设计应用,那么此时就要获取全部的接口信息 //当前的类为InvocationHandler接口子类,所以使用this描述的是本类的实例化对象 return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; if (before()){ //此时代理方法中需要进业务方法的反射调用,需要提供实例化对象(this.object),Method对象(method),参数(args) result = method.invoke(this.object,args); after(); } return result; } public boolean before(){ System.out.println("建立连接*****连接成功"); return true; } public void after(){ System.out.println("接收成功*****关闭连接"); } }
测试类:
package com.dynamicProxy.learn; /** * Created on 2020/2/28 * Package com.dynamicProxy.learn * * @author dsy */ public class ServerProxyTest { public static void main(String[] args) { IMessage iMessage = (IMessage) new ServerProxy().bind(new MessageImpl()); iMessage.message("Hi ,Alice"); } }
打印输出:
建立连接*****连接成功
发送内容:Hi ,Alice
接收成功*****关闭连接
这就实现了一个动态代理,接下来我们分析这个代理类ServerProxy 中用到了哪些新的东西:
1. 首先这个类实现了InvocationHandler 这个接口,那这个InvocationHandler 接口是干什么的呢,我们打开源码:
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
发现接口中只有一个方法invoke()与反射有关,正是他来处理代理实例上的方法调用并返回结果,三个参数为:
2. Proxy.newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
该方法返回指定接口的代理类的实例,也就是创建并返回动态代理的对象,有三个参数:
这只是对代理模式的简单论述,里面有很多知识有待我去考察,毕竟我还是个小白。
本篇动态代理的例子来源于李兴华老师的讲解,本篇没看懂的朋友们强烈建议点进去看看,或许对你有帮助!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。