黑马程序员技术交流社区
标题: 牧紫小岩_代里设计模式与反射 [打印本页]
作者: mvplee 时间: 2013-6-11 11:56
标题: 牧紫小岩_代里设计模式与反射
本帖最后由 mvplee 于 2013-6-11 15:01 编辑
在学习反射时就对反射的应用地方很费解,在学习代里设计模式时终于用到了反射,也算用反射小试牛刀。
学习过程中忽略了论坛技术分,有点郁闷,没想到技术分会成为一个问题。
所以有了打算分享自己学习笔记的想法,作为技术人员还是应该有点“共享”、“开源”、精神的,当然了,醉翁之意还是赚点技术分。
代理设计模式简介:代理设计就是指由一个代理主题来操作真是主题,真实主题操作具体的业务,而代理主题负责相关业务,代理à真实à具体业务。
Windows系统提供的快捷方式,可以使任何一个对象同时出现在多个地方而不必修改原始对象。对快捷方式的调用与对原始对象的调用是一样的,快捷方式对于客户端是完全透明的。快捷方式被删除了,不会影响原始对象,但原始对象被删除后,快捷方式将不能使用,这就是一种代理模式的体现。
代理模式的结构:抽象主题:声明真实主题和代理主题的共同接口,这样任何可以使用真是主题的地方都可以使用代理主题。
代理主题:代理主题内含有对真是主题对象的引用,从而使代理主题操作真是主题。代理主题提供一个与真实主题相同的接口,这样就可以在任何时候替代真实主题。
真实主题:代理主题所引用的真实主题。静态代理:
定义代理与真实主题的共同接口:ISubject- public interface ISubject {
- public String print() throws Exception;
- }
复制代码定义真实主题,真实主题实现抽象主题接口,并且会被代理主题所引用:实现ISubject接口
- public class ReaSubjectImpl implements ISubject {
- @Override
- public String print() throws Exception {
- return "This is print() in RealSubject.class!!!";
- }
- }
复制代码定义代理主题:代里类中通过构造接收ISubject接口的子类对象
- public class ProxySubjectImpl implements ISubject {
- private ISubject subject;
- public ProxySubjectImpl(ISubject subject) {
- this.subject = subject;
- }
- @Override
- public String print() throws Exception {
- System.out.println(this.before()); // 调用代理类中的主题
- System.out.println(subject.print()); // 调用真实类主题
- System.out.println(this.after()); // 调用代理类中的主题
- return "Proxy is ending!!!";
- }
- public String before() {
- return "This is before() in ProxySubject.class!!!";
- }
- public String after() {
- return "This is after() in ProxySubject.class!!!";
- }
- }
复制代码测试:
- public class TestStaticProxy {
- public static void main(String[] args) throws Exception {
- ISubject subject = null;
- //像代理主题传入真是主题的引用
- subject = new ProxySubjectImpl((ISubject) new ReaSubjectImpl());
- System.out.println(subject.print());
- }
- }
复制代码Sequence图:
作者: mvplee 时间: 2013-6-11 12:03
本帖最后由 mvplee 于 2013-6-11 12:06 编辑
动态代理:
静态代理的缺点是每一个代理类只能为一个接口提供服务,很多个接口就需要有很多个代理类,最好是能有一个类可完成任意接口的代理。java.lang.reflect包中提供了三个直接支持代理模式的类:Proxy、InvocationHandler、Method。Proxy类提供了一个创建代理对象的方法:- Public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
复制代码newProxyInstance()可以直接创建动态代理对象,该代理对象实现了参数中interfaces指定的所有接口,执行代理对象的每个方法时都会被替换为InvocationHandler接口的invoke(),newProxyInstance()也被要求传入一个InvocationHandler的实例对象。程序每生成一个代理类对象都有一个与之关联的InvocationHandler对象。
InvocationHandler中的invoke():- Object invoke(Object proxy,Method method,Object[] args)throws Throwable
复制代码 proxy:被动态代理的对象 method:正在调用的方法 args:调用被代里对象时传入的参数Proxy类能能够在程序运行时自动创建真实对象的代理对象,当有代理对象后,对真实对象的方法进行调用时会首先分派给InvocationHandler接口,在接口的invoke()方法中截获对真实对象方法的调用,加入额外的操作,就实现了动态代理的功能。调用真实类中的方法时就会调用invoke()。范例1:为一个Vector类提供一个代理对象,当Vector类调用任何方法之前、之后打印两条信息,表明当调用Vector中的方法时,可以被InvocationHandler接口中的invoke()截获,并实现代理功能。
- public class VectorProxy implements InvocationHandler {
- private Object proxyObj;
- public VectorProxy(Object proxyObj) {
- this.proxyObj = proxyObj;
- }
- /**
- * 定义静态工厂方法,接收被代理的对象
- * @param obj
- * @return
- */
- public static Object factory(Object obj) {
- Class<?> cls = obj.getClass();
- /* 第三个参数无法使用this,因为在静态工厂方法中,static与this冲突 */
- return Proxy.newProxyInstance(cls.getClassLoader(),
- cls.getInterfaces(), new VectorProxy(obj));
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("befroe overried invoke()-->" + method);
- if (args != null) {
- for (Object o : args)
- System.out.println(o + "\t");
- }else {
- System.out.println("args is null in overried invoke()");
- }
- Object obj = method.invoke(proxyObj, args);
- System.out.println("after overried invoke()-->" + method);
- return obj;
- }
- public static void main(String[] args) {
- @SuppressWarnings({ "unchecked", "rawtypes" })
- List<String> list = (List<String>) VectorProxy.factory(new Vector());
- list.add("New");
- System.out.println();
- list.add("York");
- System.out.println(list);
- }
- }
复制代码数出结果: befroe overried invoke()-->public abstract booleanjava.util.List.add(java.lang.Object) New after overried invoke()-->public abstract booleanjava.util.List.add(java.lang.Object)
befroe overried invoke()-->public abstract booleanjava.util.List.add(java.lang.Object) York after overried invoke()-->public abstract booleanjava.util.List.add(java.lang.Object)
befroe overried invoke()-->public java.lang.Stringjava.lang.Object.toString() args is null in overried invoke() after overried invoke()-->public java.lang.Stringjava.lang.Object.toString() [New, York]
|
数出结果显示了在调用Vector类中add()的方法时打印了befroe、after两条信息,在直接打印集合时,因为没有参数,agrs为空的信息也打印了。代理对象截获了Vector对象的所有应用。
Sequece图:
作者: mvplee 时间: 2013-6-11 12:04
本帖最后由 mvplee 于 2013-6-11 12:06 编辑
例2:把之前的静态代理,改成动态代理,实现代理功能
定义代理与真实类的共同接口:
- public interface ISubject {
- public String print() throws Exception;
- }
复制代码定义动态代理类,实现InvocationHandler接口,与之前的静态代理类完全不一样
- public class DynamicProxy implements InvocationHandler {
- private Object targetObject; // 被代理的对象
- public Object createProxyInstance(Object targetObject) {
- this.targetObject = targetObject;
- // Proxy为专门完成代理的操作类
- return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
- targetObject.getClass().getInterfaces(), this);
- // newProxyInstance(加载接口的实现类(类的加载器),真实类实现的接口, 得到InvocationHandler接口的子类(也就是本类DynamicProxy))
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println(proxyer()); // 调用真实类前所执行的方法
- // 调用真实类中的方法
- Object obj = method.invoke(targetObject, args);
- return obj;
- }
- private String proxyer() {
- return "This is proxyer in invode()!!!";
- }
- }
复制代码测试类:
- public class DynamicProxyTest {
- public static void main(String[] args) throws Exception {
- DynamicProxy dProxy = new DynamicProxy();
- ISubject subject = (ISubject) dProxy.createProxyInstance(new RealSubjectImpl());
- System.out.println(subject.print());
- }
- }
- 打印结果:
- This is proxyer in invode()!!!
- This is RealSubject!!!
复制代码例3:采用匿名内部类的方式代理Collection接口
- public class DynamicProxyTest{
- public static void main(String[] args) throws Exception {
- Class<?> clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
- Collection c = (Collection) Proxy.newProxyInstance(
- Collection.class.getClassLoader(),
- new Class[]{Collection.class},
- new InvocationHandler(){
- List list = null;
- @SuppressWarnings("rawtypes")
- @Override
- public Object invoke(Object proxy, Method method,
- Object[] args) throws Throwable {
- if(list==null)
- list = new ArrayList();
- return method.invoke(list, args);
- }
- });
- c.add("A");
- c.add("B");
- c.add("C");
- System.out.println(c.size());
- System.out.println(c);
- System.out.println(c.getClass());
- }
- }
复制代码
以上就是我学习动态代里的笔记,参考了毕向东老师的视屏、张孝祥老师的视频、阎宏《Java与模式》、李刚《疯狂Java讲义》。
对于逻辑上理解InvocationHandler中的invoke(),squence图起了不小的帮助。
ProxyDemo.rar
(11.09 KB, 下载次数: 28)
版主,小手一抖,
俺的技术分到手。
作者: 袁梦希 时间: 2013-6-11 12:38
很用功 加油
作者: mvplee 时间: 2013-6-11 23:02
谢谢版主,太感动了!:'(:'(
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |