设计模式--代理模式Proxy(学习笔记)
来源:互联网 发布:qq炫舞头像源码 编辑:程序博客网 时间:2024/05/22 01:50
代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
类图:
模拟情景:
1.有一个Tank类,实现Moveable接口中的move(),方法,现在想要对Tank的move()方法前后做些日志记录的操作,这时就可以使用代理。
public interface Moveable {void move();}
2.Tank类
import java.util.Random;/** * 被代理对象 * @author dell * */public class Tank implements Moveable{@Overridepublic void move() {System.out.println("Tank moving...");try {Thread.sleep(new Random().nextInt(10000));} catch (InterruptedException e) {e.printStackTrace();}}}
3.代理类(TankTimerProxy)
public class TankTimerProxy implements Moveable{ private Moveable t;//被代理对象 public TankTimerProxy(Moveable t){ this.t = t; } /** * 代理的move方法,前后加自定义逻辑 * @param o 代理对象 * @param method 方法处理逻辑 */@Overridepublic void move() {long start = System.currentTimeMillis(); t.move();//被代理对象的move方法。long end = System.currentTimeMillis();System.out.println("UsedTimes: " + (end - start));}}
从上面的示例中可以看到,我们本来想使用Tank的move方法,现在通过TankTimerProxy的move()方法,间接的使用了Tank的方法,此时TankTimerProxy就是Tank的一个代理。
Java动态代理模拟:
如上:TankTimerProxy是我们手动编写的,也可称为静态代理,倘若能动态生成所需的代理类,如TankTimerProxy;则更加方便我们对被代理对象添加自定义处理逻辑。即,动态代理。
为模拟Java,声明Proxy类,使用Proxy类产生所需的各种具体代理对象,TankTimerProxy,TankLogProxy等。
import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.net.URL;import java.net.URLClassLoader;import javax.tools.JavaCompiler;import javax.tools.JavaCompiler.CompilationTask;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;/** * 代理的好处,可以对任意的对象,任意接口,实现任意的代理。 * @author dell * */public class Proxy{/** * 代理类名 */private static final String PROXYNAME = "$proxy1";/** * 模拟JDK代理 * @param infce 接口 * @param handler 代理处理逻辑 * @return * @throws Exception */public static Object newProxyInstance(Class infce,InvocationHandler handler) throws Exception{/** * Step1.1: * " @Override"+ rt +" public void move() {"+ rt +" long start = System.currentTimeMillis();"+ rt +"t.move();"+ rt +"long end = System.currentTimeMillis();"+ rt +"System.out.println(\"UsedTimes: \" + (end - start));"+ rt +"}"+ rt + */String methodStr = "";String rt = "\r\n";Method[] methods = infce.getMethods();/** * step:2 * 对方法的时间代理,且扩展麻烦。为增加不同的处理需重新创建newProxyInstance,为解决此问题, * 创建单独的处理逻辑InvocationHandler类for (Method method : methods) {methodStr += " @Override"+ rt +" public void " + method.getName() + "() {"+ rt +" long start = System.currentTimeMillis();"+ rt +"t." + method.getName() + "();"+ rt +"long end = System.currentTimeMillis();"+ rt +"System.out.println(\"UsedTimes: \" + (end - start));"+ rt +"}";}*//** * Step3: * 为接口的所有方法,动态添加处理逻辑 */for (Method method : methods) {methodStr += " @Override"+ rt +" public void " + method.getName() + "() {"+ rt +" try{" + rt +"Method md = " + infce.getName()+".class.getMethod(\""+method.getName()+"\");" +rt +"h.invoke(this,md);"+ rt +"}catch(Exception e){ e.printStackTrace();}"+ rt + "}";}/** * Step:1 * 上面的TankTimerProxy为手动编写,现在我们用程序自动生成。 * 首先、生成TankTimerProxy类的字符串src,写入到磁盘文件 * 然后、编译生成的文件,生成class文件 * 最后、把生成的class文件load内存并创建TankTimerProxy类的对象 */String src = "package com.lxf.proxy;" + rt +"import java.lang.reflect.Method;"+ rt +"public class " + PROXYNAME + " implements "+infce.getName()+"{"+ rt +" private InvocationHandler h;"+ rt +" public " + PROXYNAME + "(InvocationHandler h) {"+ rt +" this.h = h;"+ rt +" }"+ rt +methodStr + rt +"}";String fileName = "D:/src/com/lxf/proxy/" + PROXYNAME + ".java";//String fileName = System.getProperties().getProperty("user.dir")+"/src/com/lxf/proxy/TankTimerProxy.java";System.out.println(fileName);File file = new File(fileName);try {FileWriter fw = new FileWriter(file);fw.write(src);fw.flush();fw.close();} catch (IOException e) {e.printStackTrace();}//compileJavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);Iterable units = fileMgr.getJavaFileObjects(fileName);CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);t.call();fileMgr.close();//load into memory and create an instance URL[] urls = new URL[]{new URL("file:/"+"D:/src/")};URLClassLoader ul = new URLClassLoader(urls);//使用classLoader时,必须保证.class文件在classpath路径中,所有为保证class可在任何位置, //使用URLClassLoaderClass c = ul.loadClass("com.lxf.proxy." + PROXYNAME);//c:类的二进制码对象System.out.println(c);Constructor cstr = c.getConstructor(InvocationHandler.class);//c.newInstance(),调用的是无参构造方法。//Moveable m = (Moveable) cstr.newInstance(new Tank());//m.move();Object m = cstr.newInstance(handler);return m;}}自动生成的代理类存储在硬盘中,当然此类对用户是透明的,用户不用了解此列就可以实现对Tank的代理。
d:/src/com/lxf/proxy/$proxy1.javapackage com.lxf.proxy;import java.lang.reflect.Method;public class $proxy1 implements com.lxf.proxy.Moveable{ private InvocationHandler h; public $proxy1(InvocationHandler h) { this.h = h; } @Override public void move() { try{ Method md = com.lxf.proxy.Moveable.class.getMethod("move"); h.invoke(this,md); }catch(Exception e){ e.printStackTrace();} }}
为了方便的在方法前后添加处理逻辑(指定处理方式)如:添加日志,时间。即动态指定对方法的处理,所以定义InovactionHandler接口,定义代理对被代理对象的处理方式。
public interface InvocationHandler {/** * 代理处理方式 * @param o 代理对象 * @param method 被代理对象的方法 */public void invoke(Object o, Method method);}
各种具体的代理对象,通过实现此接口来实现。
import java.lang.reflect.Method;/** * 自定义代理处理逻辑 * @author dell * */public class TimerHandler implements InvocationHandler {/** * 被代理对象 */private Object target;public TimerHandler(Moveable obj) {this.target = obj;}/** * 前后加自定义逻辑 * @param o 代理对象 * @param method 方法处理逻辑 */@Overridepublic void invoke(Object o, Method method) {long start = System.currentTimeMillis();System.out.println("o Name: "+o.getClass().getName());try {/** * 对带有指定参数的指定对象(target)调用由此 Method 对象表示的底层方法 * 然后,调用被代理对象的方法 */method.invoke(target);} catch (Exception e) {e.printStackTrace();}long end = System.currentTimeMillis();System.out.println("UsedTimes: " + (end - start));}}
客户端调用:
public class Client {public static void main(String[] args) throws Exception {Moveable tank = new Tank();InvocationHandler ih = new TimerHandler(tank);Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class,ih);m.move();}}
当然,上面使用了策略模式,方便对添加不同的处理逻辑。
至此,简单的Java 代理就模拟出来了。以上是自己听课(尚学堂:马士兵)《设计模式》所做记录,仅供学习。
0 0
- [设计模式学习笔记]PROXY(代理)
- 设计模式学习笔记--代理(Proxy)模式
- 设计模式学习笔记十三(Proxy代理模式)
- 【设计模式】学习笔记15:代理模式(Proxy Pattern)
- 设计模式学习笔记---代理模式Proxy(Java版)
- 设计模式--代理模式Proxy(学习笔记)
- 设计模式学习笔记十六:代理模式(Proxy Pattern)
- 设计模式学习笔记—代理模式(Proxy)
- 《设计模式》学习笔记--代理Proxy
- 设计模式学习笔记(十三)——Proxy代理
- 设计模式学习笔记(五)之代理模式(Proxy)
- java 设计模式学习笔记六 proxy代理模式
- 设计模式--学习笔记--代理模式Proxy--基础篇
- 设计模式学习笔记——代理(Proxy)模式
- C#面向对象设计模式纵横谈 学习笔记13 Proxy代理模式(结构型模式)
- 设计模式 笔记 代理模式 Proxy
- 设计模式学习7 -- Proxy:代理模式
- 设计模式学习-Proxy(代理模式)
- X264的ARMV7-a的交叉编译及优化运行
- sysfs--初窥门径
- 黑马程序员-OC语言基础:Foundation框架小结
- CSS 优化
- C/C++字符串转换为整型
- 设计模式--代理模式Proxy(学习笔记)
- SpringMVC入门
- java web 开发乱码总结
- 6ZigZag Conversion
- Mahout推荐算法API详解
- poj1088(记忆化搜索)
- ios开发常用的第三方库
- 【leetcode】28. Implement strStr()
- 详解Objective-C runtime