使用继承实现(继承)
使用实现接口实现(组合)
//继承 public class Tank { public void move() { System.out.println("Tank is moving ~~~"); } } //继承基类重写里面的方法对其进行扩展(对Tank类的move()方法加上获取运行时间的代码) public class TimeHandlerTank extends Tank { @Override public void move() { long start = System.currentTimeMillis(); super.move(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("move时间: " + String.valueOf(end - start)); } } public static void main(String[] args) { new TimeHandlerTank().move(); } //结果 Tank is moveing~~~ move时间: 1003 //组合 public interface Moveable { void move(); } public class Tank implements Moveable { public void move() { System.out.println("Tank is moveing~~~"); } } //通过构造方法传入Tank public class TimeHandler implements Moveable{ private Moveable moveable ; public TimeHandler(Moveable moveable) { this.moveable = moveable; } //实现move()方法的时候,调用Tank的move()方法,同时加上获取运行时间的代码 public void move() { long start = System.currentTimeMillis(); moveable.move(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("move时间: " + String.valueOf(end - start)); } } public static void main(String[] args) { Moveable tank = new Tank(); new TimeHandler(tank).move(); }
使用继承的方式就是继续继承重写方法,这样的话就会出现好多类(类爆炸),如果使用实现接口的方式(组合)将会避免这个问题。
//组合实现,对于上面组合的代码添加LogHandler类 public class LogHandler implements Moveable{ private Moveable moveable; public LogHandler(Moveable moveable) { this.moveable = moveable; } public void move() { moveable.move(); System.out.println("记录日志~~~~"); } } //main方法修改如下: public static void main(String[] args) { Moveable tank = new Tank(); new LogHandler(new TimeHandler(tank)).move(); } 结果: Tank is moveing~~~ move时间: 1005 记录日志~~~~
虽然可以通过编写hanler来扩展类,但是这样的话会产生的大量的类,如何能达到这样的效果又不产生大量的类呢 ,其实通过反射+动态编译便可以解决。其实jdk就是这样实现的,下面是jdk动态代理的例子:
//定义接口 public interface ForumService { void removeTopic(int topicId); void removeForum(int forumId); } //实现接口 public class ForumServiceImpl implements ForumService { public void removeTopic(int topicId) { System.out.println("模拟删除topic记录:" + topicId); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } public void removeForum(int forumId) { System.out.println("模拟删除formId:" + forumId); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } //运行时间代码(横切代码) public class PerformanceMonitor { public static void begin(String method){ System.out.println("begin monitor..."); } public static void end(){ System.out.println("end monitor"); } } //将目标业务类和横切代码编制在一起 public class PerformanceHandler implements InvocationHandler { private Object target; public PerformanceHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PerformanceMonitor.begin(target.getClass().getName() + "." + method.getName()); Object obj = method.invoke(target, args); PerformanceMonitor.end(); return obj; } } // public class TestForumService { public static void main(String[] args) { //希望被代理的目标类 ForumService target = new ForumServiceImpl(); //将目标业务类和横切代码编制在一起 PerformanceHandler handler = new PerformanceHandler(target); //返回代理对象 ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); proxy.removeForum(10); System.out.println("*****************"); proxy.removeTopic(120); } } //结果: begin monitor... 模拟删除formId:10 end monitor ***************** begin monitor... 模拟删除topic记录:120 end monitor
//定义被代理对象的类必须实现的接口 public interface Moveable { void move(); } //被代理对象实现接口 public class Tank implements Moveable { public void move() { System.out.println("Tank Moving..."); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } } } //反射调用被代理对象接口 public interface InvocationHandler { public void invoke(Object o, Method m); } //实现反射调用被代理对象接口 public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { super(); this.target = target; } public void invoke(Object o, Method m) { long start = System.currentTimeMillis(); System.out.println("starttime:" + start); System.out.println(o.getClass().getName()); try { m.invoke(target); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("time:" + (end - start)); } } //产生代理对象 public class Proxy { public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM String methodStr = ""; String rt = "\r\n"; Method[] methods = infce.getMethods(); /* for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " long start = System.currentTimeMillis();" + rt + " System.out.println(\"starttime:\" + start);" + rt + " t." + m.getName() + "();" + rt + " long end = System.currentTimeMillis();" + rt + " System.out.println(\"time:\" + (end-start));" + rt + "}"; } */ for(Method m : methods) { methodStr += rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt + "}"; } String src = "package com.bjsxt.proxy;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy1 implements " + infce.getName() + "{" + rt + " public $Proxy1(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " com.bjsxt.proxy.InvocationHandler h;" + rt + methodStr + "}"; String fileName = "/Users/wjk/myproject/test/design_pattern/src/main/java/com/bjsxt/proxy/$Proxy1.java"; File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close(); //compile(Java动态编译) JavaCompiler 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:/" + "/Users/wjk/myproject/test/design_pattern/src/main/java")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1"); System.out.println(c); Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); //m.move(); return m; } } public class Client { public static void main(String[] args) throws Exception { Tank t = new Tank(); InvocationHandler h = new TimeHandler(t); Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h); m.move(); } } //结果 class com.bjsxt.proxy.$Proxy1 starttime:1452505387375 com.bjsxt.proxy.$Proxy1 Tank Moving... time:9798
参考资料:
《Spring3.x企业应用开发实践》
《马士兵——设计模式》