场景:
福尔摩斯一直想送礼物给花生,但是羞于直接赠送,于是想到让房东太太去帮忙送礼物.编程如何实现呢?
定义:
为其他对象提供一种代理以控制对这个对象的访问。
角色:
Proxy:代理对象.有下列功能:
实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。
持有一个具体目标对象的引用,可以在需要时调用具体的目标对象。
可以控制对目标对象的访问,并可以负责创建和删除它。
package com.kris.study; public class Proxy implements Subject { private RealSubject realSubject = null; public Proxy(RealSubject realSubject){ this.realSubject = realSubject; } @Override public void request() { System.out.println("代理之前做一些操作。。。。。。"); realSubject.request(); System.out.println("代理之后做一些操作。。。。。。"); } }
Subject:目标接口
package com.kris.study; public interface Subject { public void request(); }
RealSubject:具体的目标对象,被代理的对象
package com.kris.study; public class RealSubject implements Subject { @Override public void request() { //执行具体的功能处理 } }
下面用代理模式实现场景。
package com.kris.study; public interface SendGift { public void send(); }
package com.kris.study; public class Holmes implements SendGift { @Override public void send() { System.out.println("送礼物给花生---来自福尔摩斯"); } }
package com.kris.study; public class FangDongTaiTai implements SendGift { private Holmes holmes = null; public FangDongTaiTai(Holmes holmes){ this.holmes = holmes; } @Override public void send() { System.out.println("亲爱的花生,老福让我给你带个东西"); holmes.send(); } }
package com.kris.study; public class Client { public static void main(String[] args) { Holmes holmes = new Holmes(); SendGift sendGift = new FangDongTaiTai(holmes); sendGift.send(); } }
上面讲的都是静态代理,JAVA中提供了一套动态代理的机制,更加灵活。目前JAVA的动态代理只支持接口,若要实现类的代理,可以使用cglib.
步骤:
1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法。
2. 创建被代理的类以及接口
3. 通过Proxy的静态方法new ProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
创建一个代理,这个代理无论执行什么方法都会转到Handler中的invoke方法去调用.
4. 通过代理调用方法
上面第一步中的invoke方法参数说明
pubilc Object invoke(Object obj,Method method,Object[] args)
obj:代理类
method:被代理的方法
args:方法的参数
动态代理实现场景:
上面的SendGift接口和Holmes类都没变化,现在把房东太太的实现变更为实现InvocationHandler
package com.kris.study; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class FangDongTaiTai implements InvocationHandler { private SendGift holmes = null; public SendGift bindObject(Holmes holmes){ this.holmes = holmes; SendGift sendProxy = (SendGift) Proxy.newProxyInstance(holmes.getClass().getClassLoader(), holmes.getClass().getInterfaces(), this); return sendProxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("亲爱的花生,这是大福给你的"); return method.invoke(holmes, args); } }
package com.kris.study; public class Client { public static void main(String[] args) { Holmes holmes = new Holmes(); FangDongTaiTai giftSendHandler = new FangDongTaiTai(); SendGift proxy = giftSendHandler.bindObject(holmes); proxy.send(); } }
思考:
代理模式的本质:控制对象的访问
特点:
远程代理:Android中的Binder机制就是通过代理实现,本地通过一个代理对象去调用远程Service的方法。
虚代理:比如加载数据库中所有人员数据,页面上只显示人员名字,点击名字可以查看人员详细信息,这样先用代理对象加载所有人员的名字和ID.当真正需要看其他详细信息时,用代理对象再次去数据库加载所有人员数据。
保护代理:对目标对象的访问进行权限的管控,在代理对象中需要满足某种条件才能调用目标对象的方法。
智能指引:在代理方法的前后执行一些附加的业务逻辑,AOP切面。
何时使用代理:
1.需要为一个对象在不同的地址空间提供局部代表的时候,可以使用远程代理
2.需要创建开销很大的对象时,可以使用虚代理。
3.需要控制对原始对象的访问的时候,可以使用保护代理
4.需要在访问对象执行一些附加操作的时候,可以使用智能指引代理