• 通过两种代理方式来隔离第三方库


    开发的过程中会不可避免的引用一些第三方库,比如网络请求库、图片加载库等等。就拿图片加载库来说,程序中不会只有一个地方来引用到此库,可能有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类即可,而代理类不需要任何变动便可以在不同动态库之间切换。

  • 相关阅读:
    Android打包报错 Export aborted because fatal lint errors were found. These are listed in the Lint View
    jqMobi 更小更快的移动框架
    php报错:Call to undefined function get_magic_quotes_gpc()
    php:字符窜截取substr和mb_substr
    Warning Creating default object from empty value in xxx.php
    linux下安装xampp
    程序员找不女朋友的原因
    键盘各种按键对应的ASII码
    Read All About It-Attraction舞团
    What are words-Chris Medina
  • 原文地址:https://www.cnblogs.com/liming1593/p/6534446.html
Copyright © 2020-2023  润新知