zoukankan      html  css  js  c++  java
  • 通过两种代理方式来隔离第三方库

    开发的过程中会不可避免的引用一些第三方库,比如网络请求库、图片加载库等等。就拿图片加载库来说,程序中不会只有一个地方来引用到此库,可能有N个类会用到此库来显示图片。当我们后期需要更换其它第三方库时问题就来了,我们得改多少代码,程序中到底有多少地方引用了这个第三方库,万一改代码的时候引发了其他的bug怎么办。

    问题来了我们应该如何避免这种“牵一发而动全身”的囧况。

    图1,普通引用第三方库的做法

    图2,重新设计之后的引用流程

    从上图我们能看到我们通过一个中间层来引用“第三方图片加载库”。这样做的好处是不管第三方图片加载库你换成Picasso还是Glide我们改变的只是这个中间层,其他的我们一行代码都不需要改动。

    1、用静态代理来实现。

    首先抽象一个ImageLoader接口

    public interface ImageLoader() {
    	
    	void displayImage(String url, ImageView imageView, int defaultImage);
    }  
    

    比如当前是使用第一种第三方库First来展示项目中的图片,就建一个ImageLoaderSubject类来实现上面的接口

    public class ImageLoaderSubject implements ImageLoader{
    	
    	public ImageLoaderSubject() {
    	}
    	
    	@Override
    	public void displayImage(String url, ImageView imageView, int defaultImage) {
    		
    		First.loadImage(url, imageView, defaultImage);
    	}
    }  
    

    接下来我们写一个代理类来帮我们实现图片加载的任务

    public class ImageLoaderProxy implements ImageLoader {
    	
    	private ImageLoader imageLoader;//作为代理类的一个属性
    	private ImageLoaderProxy imageLoaderProxy;
    
    	public static ImageLoaderProxy newInstance() {
    		if(imageLoaderProxy == null) {
    			imageLoaderProxy = new ImageLoaderProxy();
    		}
    		return imageLoaderProxy;
    	}
    	
    	public ImageLoaderProxy() {
    		
    		this.imageLoader = new ImageLoaderSubject();
    	}
    
    	@Override
    	public void displayImage(String url, ImageView imageView, int defaultImage) {
    		
    		System.out.println("do some thing");
    		imageLoader.displayImage(url, imageView, defaultImage);
    		System.out.println("do other thing");
    	}
    }  
    

    这样我们在程序中再次引用第三方库时可以直接使用下面的方法

    ImageLoaderProxy.newInstance().displayImage(url, imageView, defaultImage);  
    

    当我们换成第二种第三方库来完成图片加载时 ,我们只需为该第三方库新建一个调用的类ImageLoaderSubject2 实现,并将代理类中的这行代码 imageLoaderProxy = new UniversalImageLoader();换成imageLoaderProxy = new ImageLoaderSubject2() 即可。

    2、用动态代理来实现。

    还用一种动态代理的方法,可以不必为特定的接口操作特定代理对象。可使用一个处理者代理多个接口的操作对象。
    处理者必须操作java.lang.reflect.InvocationHandler接口
    设计一个ImagerLoaderHandler类

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class  ImageLoaderHandler implements InvocationHandler {
    	
    	private Object target;
    	
    	public Object bind(Object target) {
        	this.target = target;
        	return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
        	Object result = null;
        	try {
            	result = method.invoke(target, args);
        	} catch (IllegalAccessException | IllegalArgumentException e) {
            	System.out.println(e.toString());
        	}
        	return result;
    	}
    }
    

    在需要调用图片加载的地方使用ImageLoaderHandler的bind()方法来绑定被代理的对象。

    ImageLoaderHandler imageLoaderHandler = new ImageLoaderHandler();
    ImageLoader imageLoaderProxy = (ImageLoader) imageLoaderHandler.bind(new ImageLoaderSubject());
    imageLoaderProxy.displayImage(url, imageView, defaultImage);  
    

    主要是使用Proxy.newProxyInstance()方法建立代理对象,调用时必须指定类加载器,告知要代理的借口,以及接口上定义的方法被调用时的处理者(InvocationHandler实例),Proxy.newProxyInstance()方法底层会使用原生方式生成代理对象的class实例,并利用它来生成代理对象,代理对象会指定要代理的接口。

    这样使代理类更具有通用型,每次只需要改动ImageLoaderSubject类即可,而代理类不需要任何变动便可以在不同动态库之间切换。

  • 相关阅读:
    mysql 函数 存储过程 事件(event) job 模板
    protobuf 无proto 解码 decode 语言 java python
    mitmproxy fiddler 抓包 填坑
    android adb 常用命令
    android机器人 模拟 踩坑过程
    RabbitMQ添加新用户并支持远程访问
    Windows下RabbitMQ安装及配置
    Java mybatis mysql 常用数据类型对应关系
    easyExcel 踩坑
    linux防火墙查看状态firewall、iptable
  • 原文地址:https://www.cnblogs.com/liming1593/p/6534446.html
Copyright © 2011-2022 走看看