博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态代理相对于静态代理的优势
阅读量:4502 次
发布时间:2019-06-08

本文共 5510 字,大约阅读时间需要 18 分钟。

整理自知乎;整理自知乎;整理自知乎

静态代理与动态代理

代理模式是一种设计模式,典型的分为静态代理和动态代理。
先讲静态代理
首先给个场景,现有个FontProvider接口,用于获取字体
public interface FontProvider {    Font getFont(String name);}

具体的实现类有三种,分别是FontProviderFromDisk,FontProviderFromNet,FontProviderFromSystem

public class FontProviderFromDisk implements FontProvider {    @Override    public Font getFont(String name) {        System.out.printf("get %s from disk\n",name);        return null;    }}public class FontProviderFromNet implements FontProvider {    @Override    public Font getFont(String name) {        System.out.printf("get %s from net\n",name);        return null;    }}public class FontProviderFromSystem implements FontProvider {    @Override    public Font getFont(String name) {        System.out.printf("get %s from system\n",name);        return null;    }}

然后我们使用上面FontProvider的实现类,获取字体,但是我突然想增加个缓存的功能以提高效率!怎么办呢?第一种就是在各个FontProvider实现类中添加缓存的代码,这样显然不理想,万一我这有一百个FontProvider实现类呢,那岂不是得修改一百多个FontProvider的实现类?第二种就是利用静态代理控制方法的调用(从缓存中获取成功,则不调用委托类的getFont()方法,获取失败则老老实实调用委托类的getFont()方法),这样即使有一百个FontProvider实现类也可以保证就仅有一份实现字体缓存的代码。

public class CachedFontProvider implements FontProvider {    private FontProvider fontProvider; //委托类    private Map
cached; public CachedFontProvider(FontProvider fontProvider) { this.fontProvider = fontProvider; cached = new HashMap<>(); } /** * 绑定委托类,依靠这个方法可以运行时更换委托类 * @param fontProvider */ public void bindTo(FontProvider fontProvider) { this.fontProvider = fontProvider; cached.clear(); //委托类更换,缓存清除 } @Override public Font getFont(String name) { Font font = cached.get(name); if(font == null) { //从缓存中获取失败,调用委托类的getFont()方法 font = fontProvider.getFont(name); cached.put(name, font); return font; } else { //从缓存中获取成功,无需调用委托类的getFont()方法 return font; } }}
自此,静态代理的作用就体现出来了,它可以控制方法的调用,处理方法调用的结果。
 
现在,我又添加了ColorProvider,ShapeProvider两个结果,各自也拥有若干实现类,现在我也想为各个XXXProvider添加缓存功能,咋办?
这还不简单,静态代理啊,好不好?!
public class CachedColorProvider implements ColorProvider {    private ColorProvider colorProvider; //委托类    private Map
cached; public CachedColorProvider(ColorProvider colorProvider) { this.colorProvider = colorProvider; cached = new HashMap<>(); } /** * 绑定委托类,依靠这个方法可以运行时更换委托类 * @param ColorProvider */ public void bindTo(ColorProvider colorProvider) { this.colorProvider = colorProvider; cached.clear(); //委托类更换,缓存清除 } @Override public Color getColor(String name) { Color color = cached.get(name); if(Color == null) { //从缓存中获取失败,调用委托类的getColor()方法 Color = ColorProvider.getColor(name); cached.put(name, color); return color; } else { //从缓存中获取成功,无需调用委托类的getColor()方法 return color; } }}public class CachedShapeProvider implements ShapeProvider { private ShapeProvider shapeProvider; //委托类 private Map
cached; public CachedShapeProvider(ShapeProvider shapeProvider) { this.shapeProvider = shapeProvider; cached = new HashMap<>(); } /** * 绑定委托类,依靠这个方法可以运行时更换委托类 * @param shapeProvider */ public void bindTo(ShapeProvider shapeProvider) { this.shapeProvider = shapeProvider; cached.clear(); //委托类更换,缓存清除 } @Override public Shape getShape(String name) { Shape shape = cached.get(name); if(shape == null) { //从缓存中获取失败,调用委托类的getShape()方法 shape = shapeProvider.getShape(name); cached.put(name, shape); return shape; } else { //从缓存中获取成功,无需调用委托类的getShape()方法 return shape; } }}
上面的代码乍看实现了功能,但是仍不理想,代码冗余太高,还是那个“万一”,万一我这还有ImageProvider、MusicProvider等等数百个XXXProvider呢?为每个XXXPrivder提供一个CachedXXXProvider自然不现实。
这就是静态代理的不足之处,它的实现方式以接口实现的形式与委托类绑定在了一起,所以决定了一个委托类对应一个代理类的模式(FontProvider对应CachedFontProvider,ShapeProvider对应CachedShapeProvider,ColorProvider对应CachedColorProvider),如果在委托类很多的应用场景,静态代理显然力不从心。这个时候,使用动态代理就可以打破这种限制。
 
public class CachedProviderHandler implements InvocationHandler {    private Map
cached = new HashMap<>(); private Object target; public CachedProviderHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Type[] types = method.getParameterTypes(); if (method.getName().matches("get.+") && (types.length == 1) && (types[0] == String.class)) { //控制getFont(),getColor(),getShape()等方法的访问 String key = (String) args[0]; Object value = cached.get(key); if (value == null) { value = method.invoke(target, args); cached.put(key, value); } return value; } return method.invoke(target, args); }}//生成FontProvider的代理对象Proxy.newProxyInstance(FontProvider.class.getClassLoader(),new Class[]{FontProvider.class},new CachedProviderHandler(new FontProviderFromDisk()));//生成ShapeProvider的代理对象Proxy.newProxyInstance(ShapeProvider.class.getClassLoader(),new Class[]{ShapeProvider.class},new CachedProviderHandler(new ShapeProviderFromDisk()));...
一个 CachedProviderHandler就可以代理 FontProvider,ShapeProvider,ColorProvider多个XXXProvider,岂不美哉?

总结

至此,我们知道动态代理相对于静态代理的优势:就静态代理而言,在委托类特别多的应用场景,就要相应的添加许多的代理类,这显然增加了应用程序的复杂度,而使用动态代理就可以
减少代理类的数量,相对降低了应用程序的复杂度

引用

1.

转载于:https://www.cnblogs.com/fudashi/p/7117365.html

你可能感兴趣的文章
图片懒加载
查看>>
tomcat下jndi的三种配置方式
查看>>
JS moveStart和moveEnd方法(TextRange对象--查找与选择)
查看>>
textArea中的placeholder属性不起作用
查看>>
Swift 里字符串(一)概览
查看>>
温故知新 javascript 正则表达式(转载)
查看>>
XP系统无法远程桌面
查看>>
正确使用索引
查看>>
java多态
查看>>
盒覆盖 算法
查看>>
bzoj1260 [CQOI2007]涂色paint
查看>>
仿网上银行虚拟键盘脚本- keyboard.js
查看>>
makefile "=" ":=" "?=" "+="
查看>>
机会是留给有准备的人
查看>>
实战是最好的学习方式
查看>>
使用qemu-img创建虚拟磁盘文件
查看>>
JDBC
查看>>
POJ - 3237 Tree (树链剖分+线段树)
查看>>
个人网站可参考的资料
查看>>
跟随一条insert语句, 进入TiDB的源码世界(上)
查看>>