黑马程序员技术交流社区

标题: 牧紫小岩_代里设计模式与反射 [打印本页]

作者: mvplee    时间: 2013-6-11 11:56
标题: 牧紫小岩_代里设计模式与反射
本帖最后由 mvplee 于 2013-6-11 15:01 编辑

在学习反射时就对反射的应用地方很费解,在学习代里设计模式时终于用到了反射,也算用反射小试牛刀。
学习过程中忽略了论坛技术分,有点郁闷,没想到技术分会成为一个问题
所以有了打算分享自己学习笔记的想法作为技术人员还是应该有点“共享”、“开源”、精神的,当然了,醉翁之意还是赚点技术分。


代理设计模式简介:
代理设计就是指由一个代理主题来操作真是主题,真实主题操作具体的业务,而代理主题负责相关业务,代理à真实à具体业务。
       Windows系统提供的快捷方式,可以使任何一个对象同时出现在多个地方而不必修改原始对象。对快捷方式的调用与对原始对象的调用是一样的,快捷方式对于客户端是完全透明的。快捷方式被删除了,不会影响原始对象,但原始对象被删除后,快捷方式将不能使用,这就是一种代理模式的体现。

代理模式的结构:抽象主题:声明真实主题和代理主题的共同接口,这样任何可以使用真是主题的地方都可以使用代理主题。
代理主题:代理主题内含有对真是主题对象的引用,从而使代理主题操作真是主题。代理主题提供一个与真实主题相同的接口,这样就可以在任何时候替代真实主题。
真实主题:
代理主题所引用的真实主题。静态代理:

定义代理与真实主题的共同接口:ISubject
  1. public interface ISubject {
  2.         public String print() throws Exception;
  3. }
复制代码
定义真实主题,真实主题实现抽象主题接口,并且会被代理主题所引用:实现ISubject接口
  1. public class ReaSubjectImpl implements ISubject {
  2.         @Override
  3.         public String print() throws Exception {
  4.                 return "This is print() in RealSubject.class!!!";
  5.         }
  6. }
复制代码
定义代理主题:代里类中通过构造接收ISubject接口的子类对象
  1. public class ProxySubjectImpl implements ISubject {
  2.         private ISubject subject;
  3.         public ProxySubjectImpl(ISubject subject) {
  4.                 this.subject = subject;
  5.         }
  6.         @Override
  7.         public String print() throws Exception {
  8.                 System.out.println(this.before()); // 调用代理类中的主题
  9.                 System.out.println(subject.print()); // 调用真实类主题
  10.                 System.out.println(this.after()); // 调用代理类中的主题
  11.                 return "Proxy is ending!!!";
  12.         }
  13.         public String before() {
  14.                 return "This is before() in ProxySubject.class!!!";
  15.         }
  16.         public String after() {
  17.                 return "This is after() in ProxySubject.class!!!";
  18.         }
  19. }
复制代码
测试:
  1. public class TestStaticProxy {
  2.         public static void main(String[] args) throws Exception {
  3.                 ISubject subject = null;
  4.                 //像代理主题传入真是主题的引用
  5.                 subject = new ProxySubjectImpl((ISubject) new ReaSubjectImpl());
  6.                 System.out.println(subject.print());
  7.         }
  8. }
复制代码
Sequence图:





作者: mvplee    时间: 2013-6-11 12:03
本帖最后由 mvplee 于 2013-6-11 12:06 编辑

动态代理:
静态代理的缺点是每一个代理类只能为一个接口提供服务,很多个接口就需要有很多个代理类,最好是能有一个类可完成任意接口的代理。java.lang.reflect包中提供了三个直接支持代理模式的类:ProxyInvocationHandlerMethodProxy类提供了一个创建代理对象的方法:
  1. Public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
复制代码
newProxyInstance()可以直接创建动态代理对象,该代理对象实现了参数中interfaces指定的所有接口,执行代理对象的每个方法时都会被替换为InvocationHandler接口的invoke()newProxyInstance()也被要求传入一个InvocationHandler的实例对象。程序每生成一个代理类对象都有一个与之关联的InvocationHandler对象。
InvocationHandler中的invoke():
  1. Object invoke(Object proxy,Method method,Object[] args)throws Throwable
复制代码
proxy:被动态代理的对象   method:正在调用的方法   args:调用被代里对象时传入的参数Proxy类能能够在程序运行时自动创建真实对象的代理对象,当有代理对象后,对真实对象的方法进行调用时会首先分派给InvocationHandler接口,在接口的invoke()方法中截获对真实对象方法的调用,加入额外的操作,就实现了动态代理的功能。调用真实类中的方法时就会调用invoke()
范例1为一个Vector类提供一个代理对象,当Vector类调用任何方法之前、之后打印两条信息,表明当调用Vector中的方法时,可以被InvocationHandler接口中的invoke()截获,并实现代理功能。
  1. public class VectorProxy implements InvocationHandler {
  2.         private Object proxyObj;
  3.         public VectorProxy(Object proxyObj) {
  4.                 this.proxyObj = proxyObj;
  5.         }
  6.         /**
  7.          * 定义静态工厂方法,接收被代理的对象
  8.          *  @param obj
  9.          * @return
  10.          */
  11.         public static Object factory(Object obj) {
  12.                 Class<?> cls = obj.getClass();
  13.         /* 第三个参数无法使用this,因为在静态工厂方法中,static与this冲突 */
  14.                 return Proxy.newProxyInstance(cls.getClassLoader(),
  15.                                 cls.getInterfaces(), new VectorProxy(obj));
  16.         }
  17.         @Override
  18.         public Object invoke(Object proxy, Method method, Object[] args)
  19.                         throws Throwable {
  20.                 System.out.println("befroe overried invoke()-->" + method);
  21.                 if (args != null) {
  22.                         for (Object o : args)
  23.                                 System.out.println(o + "\t");
  24.                 }else {
  25.                         System.out.println("args is null in overried invoke()");
  26.                 }
  27.                 Object obj = method.invoke(proxyObj, args);
  28.                 System.out.println("after overried invoke()-->" + method);
  29.                 return obj;
  30.         }

  31.         public static void main(String[] args) {
  32.                 @SuppressWarnings({ "unchecked", "rawtypes" })
  33.                 List<String> list = (List<String>) VectorProxy.factory(new Vector());
  34.                 list.add("New");
  35.                 System.out.println();
  36.                 list.add("York");
  37.                 System.out.println(list);
  38.         }
  39. }
复制代码
数出结果:
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()的方法时打印了befroeafter两条信息,在直接打印集合时,因为没有参数,agrs为空的信息也打印了。代理对象截获了Vector对象的所有应用。

Sequece图:




作者: mvplee    时间: 2013-6-11 12:04
本帖最后由 mvplee 于 2013-6-11 12:06 编辑

2把之前的静态代理,改成动态代理,实现代理功能
定义代理与真实类的共同接口:
  1. public interface ISubject {
  2.         public String print() throws Exception;
  3. }
复制代码
定义动态代理类,实现InvocationHandler接口,与之前的静态代理类完全不一样
  1. public class DynamicProxy implements InvocationHandler {
  2.         private Object targetObject; // 被代理的对象
  3.         public Object createProxyInstance(Object targetObject) {
  4.                 this.targetObject = targetObject;
  5.                 // Proxy为专门完成代理的操作类
  6.                 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
  7.                                 targetObject.getClass().getInterfaces(), this);
  8.                 // newProxyInstance(加载接口的实现类(类的加载器),真实类实现的接口, 得到InvocationHandler接口的子类(也就是本类DynamicProxy))
  9.         }
  10.         @Override
  11.         public Object invoke(Object proxy, Method method, Object[] args)
  12.                         throws Throwable {
  13.                 System.out.println(proxyer()); // 调用真实类前所执行的方法
  14. // 调用真实类中的方法
  15.                 Object obj = method.invoke(targetObject, args);
  16.                 return obj;
  17.         }
  18.         private String proxyer() {
  19.                 return "This is proxyer in invode()!!!";
  20.         }
  21. }
复制代码
测试类:
  1. public class DynamicProxyTest {
  2.         public static void main(String[] args) throws Exception {
  3.                 DynamicProxy dProxy = new DynamicProxy();
  4.                 ISubject subject = (ISubject) dProxy.createProxyInstance(new RealSubjectImpl());
  5.                 System.out.println(subject.print());
  6.         }
  7. }
  8. 打印结果:
  9. This is proxyer in invode()!!!
  10. This is RealSubject!!!
复制代码
3采用匿名内部类的方式代理Collection接口
  1. public class DynamicProxyTest{
  2.         public static void main(String[] args) throws Exception {
  3.                 Class<?> clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
  4.                 Collection c = (Collection) Proxy.newProxyInstance(
  5.                                 Collection.class.getClassLoader(),
  6.                                 new Class[]{Collection.class},
  7.                                 new InvocationHandler(){
  8.                                         List list = null;
  9.                                         @SuppressWarnings("rawtypes")
  10.                                         @Override
  11.                                         public Object invoke(Object proxy, Method method,
  12.                                                         Object[] args) throws Throwable {
  13.                                                 if(list==null)
  14.                                                  list = new ArrayList();
  15.                                                 return method.invoke(list, args);
  16.                                         }
  17.                                 });
  18.                 c.add("A");
  19.                 c.add("B");
  20.                 c.add("C");
  21.                 System.out.println(c.size());
  22.                 System.out.println(c);
  23.                 System.out.println(c.getClass());
  24.         }
  25. }
复制代码



以上就是我学习动态代里的笔记,参考了毕向东老师的视屏、张孝祥老师的视频、阎宏《Java与模式》、李刚《疯狂Java讲义》。
对于逻辑上理解InvocationHandler中的invoke(),squence图起了不小的帮助。


ProxyDemo.rar (11.09 KB, 下载次数: 28)
版主,小手一抖
俺的技术分到手



作者: 袁梦希    时间: 2013-6-11 12:38
很用功  加油
作者: mvplee    时间: 2013-6-11 23:02
袁梦希 发表于 2013-6-11 12:38
很用功  加油

谢谢版主,太感动了!:'(:'(




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2