什么是代理模式
代理类和被代理类实现同一个接口,也就是说他们有着相同的功能,区别在于,被代理类持有代理类的引用,被代理类中所有功能的实现都是由代理类来完成的
为什么要使用代理模式
一个优秀的软件设计,对于类似功能的模块,其中相同的逻辑,应该做到抽取与封装,来保证代码的简洁和可维护性,而对于其中不同的部分,则应该提供相应的方法来进行个性化定制.
现在有三个功能相似的类,他们有很多类似的方法,首先,把这些方法抽取出来,变成一个接口,然后写一个代理类实现这个接口,所有相同的逻辑,都抽取出来放在这个代理类中,三个类再调用这个代理类来完成相应的逻辑,不同的部分则正好可以在方法中自定义
还有第二种情况,一个接口中,有很多的方法,这些方法的实现中有很多的相同之处,比如retrofit的service接口,里面的方法都是网络请求的方法,比如我们现在要对所有的网络请求加缓存,难道所有的方法中都要写一次吗,显然不符合我们的设计规范,这里就可以用动态代理.
如何设计一个静态代理模式
-
首先定义一个接口
public interface NetWorkService { //获取用户名的网络请求 String getUserName(int userId); //给文章点赞的网络请求 Boolean likedThisArticle(int articleId); }
-
接着是代理类
public class NetWorkServiceImp implements NetWorkService { @Override public String getUserName(int userId) { //这里就来一个假的实现吧 return "KingSlayer"; } @Override public Boolean likedThisArticle(int articleId) { return true; } }
-
然后是被代理类
public class NetWorkServiceProxy implements NetWorkService { private NetWorkService netWorkServiceImp; public void attach(NetWorkService netWorkServiceImp) { this.netWorkServiceImp = netWorkServiceImp; } @Override public String getUserName(int userId) { //这里提出一个新的要求,将请求结果存入缓存 String userName = netWorkServiceImp.getUserName(userId); CacheUtils.put(String.valueOf(userId), userName); return userName; } @Override public Boolean likedThisArticle(int articleId) { Boolean isActionSuccess = netWorkServiceImp.likedThisArticle(articleId); CacheUtils.put(String.valueOf(articleId), isActionSuccess); return isActionSuccess; } }
总结:上面这个静态代理完成之后,如果有别的类也需要这两个请求方法,只需要实现这个接口,然后绑定NetWorkServiceImp的对象就好了,非常的方便简洁,也利于维护
如何设计一个动态代理模式
-
首先我们来看这个静态方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); // Android-changed: sm is always null // final SecurityManager sm = System.getSecurityManager(); // if (sm != null) { // checkProxyAccess(Reflection.getCallerClass(), loader, intfs); // } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { // Android-changed: sm is always null // if (sm != null) { // checkNewProxyPermission(Reflection.getCallerClass(), cl); // } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { // Android-changed: Removed AccessController.doPrivileged cons.setAccessible(true); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
-
我们关注一下这个方法的第三个参数
public class NetWorkServiceProxyHandler implements InvocationHandler { private NetWorkService netWorkService; public NetWorkServiceProxyHandler(NetWorkService netWorkService) { this.netWorkService = netWorkService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(netWorkService, args); CacheUtils.put(String.valueOf(args[0]), invoke); return invoke; } }
在这里,我们创建一个类实现InvocationHandler接口,在这个类中,有一个invoke方法,我们拿到代理类,通过反射调用接口中所有的方法,同时也正好在这里把每个请求方法的结果都存入缓存中,就不用每个请求方法都写一遍了,我觉得这正是retrofit中通过动态代理获取service对象的原因.