代理模式(Proxy)
定义
为其他对象提供一种代理以控制对这个对象的访问。
UML结构图
例子
一个人希望去追求一个女生,但是不好意思直接送礼物给女生,所以就只有找一个女生的朋友,代表他去送礼物,和女生直接接触的并不是该追求者,而是中间的代理对象。
package com.csdhsm.designpattem.proxy; /** * @Title: GivenGift.java * @Description: 定义一个公用的接口,也就是类图中的Subject * @author: Han * @date: 2016年6月20日 下午3:43:42 */ public interface GivenGift { //送花 public void giveFlower(); //送书 public void giveBook(); //送钱 public void giveMoney(); }
女生
package com.csdhsm.designpattem.proxy; /** * @Title: SchoolGirl.java * @Description: 女生类 * @author: Han * @date: 2016年6月20日 下午3:46:45 */ public class SchoolGirl { private String name; public SchoolGirl(String name) { this.name = name; } public String getName() { return name; } }
追求者
package com.csdhsm.designpattem.proxy; /** * @Title: Pursuit.java * @Description: 追求者,但是不好意思直接给MM送礼物 * @author: Han * @date: 2016年6月20日 下午3:43:14 */ public class Pursuit implements GivenGift { private SchoolGirl mm; public Pursuit(SchoolGirl mm) { this.mm = mm; } @Override public void giveFlower() { System.out.println("给" + mm.getName() + "送花!"); } @Override public void giveBook() { System.out.println("给" + mm.getName() + "送书!"); } @Override public void giveMoney() { System.out.println("给" + mm.getName() + "送钱!"); } }
代替送礼物的人
package com.csdhsm.designpattem.proxy; /** * @Title: Proxy.java * @Description: 代理类,代替Pursuit去送东西 * @author: Han * @date: 2016年6月20日 下午3:42:51 */ public class Proxy implements GivenGift { private Pursuit pursuit; public Proxy(SchoolGirl mm) { if(pursuit == null) { pursuit = new Pursuit(mm); } } @Override public void giveFlower() { pursuit.giveFlower(); } @Override public void giveBook() { pursuit.giveBook(); } @Override public void giveMoney() { pursuit.giveMoney(); } }
客户端
package com.csdhsm.designpattem.proxy; public class Solution { public static void main(String[] args) { SchoolGirl mm = new SchoolGirl("小美"); Proxy proxy = new Proxy(mm); proxy.giveBook(); proxy.giveFlower(); proxy.giveMoney(); } }
OK,代理模式成功。
动态代理
上面的代理属于静态代理,前段时间再看AOP,研究了下动态代理,记录下来,方便以后回忆。
动态代理:在程序运行时,运用反射机制动态创建而成。
动态代理例子
package com.csdhsm.dynamicproxy; /** * @Title: Subject.java * @Description: 一个会跑,会打招呼的接口 * @author: Han * @date: 2016年6月20日 下午4:08:11 */ public interface Subject { public void run(); public void hello(String str); }
package com.csdhsm.dynamicproxy; /** * @Title: RealSubject.java * @Description: 真实的对象类 * @author: Han * @date: 2016年6月20日 下午4:10:04 */ public class RealSubject implements Subject { @Override public void run() { System.out.println("I`m running"); } @Override public void hello(String str) { System.out.println("say hello to " + str); } }
上面的两个对象一个是Subject接口,一个是RealSubject,接下来是代理对象。
package com.csdhsm.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @Title: DynamicProxy.java * @Description: 动态代理类 * @author: Han * @date: 2016年6月20日 下午4:10:35 */ public class DynamicProxy implements InvocationHandler { private Object subject; public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before-----------------"); method.invoke(subject, args); System.out.println("after------------------"); return null; } }
想要成为动态代理类,就需要实现InvocationHandler接口,该接口只有一个方法,就是invoke方法,打开API文档。
该方法是在代理实例上处理相关联的方法的时候调用该方法,我的理解是,在调用关联方法时,用该方法代替,也就是这个方法代理了原方法。
proxy参数,表示实现方法的代理实例。
method代理方法,用反射实现该方法。
args该方法的参数。
说明:很多同学会有疑问 method.invoke(subject, args); 这句是否可以写成 method.invoke(proxy, args); ,很明显是不可以的,因为proxy是代理对象实例,这样的结果会是
很明显就是一直在调用相同的方法,陷入死循环中。
客户端
package com.csdhsm.dynamicproxy; import java.lang.reflect.Proxy; public class Solution { public static void main(String[] args) { Subject subject = new RealSubject(); DynamicProxy proxy = new DynamicProxy(subject); //获取该代理对象 Subject realSubject = (Subject)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), subject.getClass().getInterfaces(), proxy); realSubject.run(); realSubject.hello("Jack"); } }
重点在与这个方法Proxy.newProxyInstance(),贴出API
这个方法返回一个代理实例,其中:
loader代理对象类加载器
interfaces接口列表,其中就是关联的方法
h代理对象
结果
OK,成功!