六大设计原则之依赖倒置原则

来源:互联网 发布:外设马淘宝 编辑:程序博客网 时间:2024/05/18 01:06

依赖倒置原则:一种特定的解耦形式,使得高层次模块不依赖低层次模块的实现细节的目的,依赖
被颠倒了。可以这么理解,实现的细节依赖于抽象。那么抽象又是什么呢?可以理解为一种约定好
的规则,在Java语言中,抽象具体指的是接口或抽象类,两者都不能直接被实例化。细节就是实现
类,即实现接口或继承抽象类而产生的类就是细节。其具体的表现为,模块间的依赖不通过细节类
发生,而是通过抽象(接口或者抽象类)发生。
以上都可以理解为面向接口编程或者面向抽象(这里指接口或者抽象类)编程。如果类与类直接直
接依赖于细节,他们之间就有直接的耦合,这样当需求变化时,往往需要同时修改依赖和被依赖者
的代码,这是我们应当避免出现的,原因就是很容易引入新bug,也限制了系统的扩展性能。
还是用第一、二篇中的例子来说明。

public class ImageLoader {    //内存缓存(直接依赖于细节),MemoryCache类参考上一篇文章   private MemoryCache mImageCache = new MemoryCache();    //线程池,线程数量为CUP的数量    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().            availableProcessors());    //UI Handler    Handler mUiHandler = new Handler(Looper.getMainLooper());    /**     * 提供外部调用显示图片的函数     *     * @param url       图片的路径     * @param imageview 显示图片的view     */    public void displayImage(final String url, final ImageView imageview) {        Bitmap bitmap = mImageCache.get(url);        if (bitmap != null) {            imageview.setImageBitmap(bitmap);            return;        }        imageview.setTag(url);        mExecutorService.submit(new Runnable() {            @Override            public void run() {                Bitmap bitmap = downloadImage(url);                if (bitmap == null) return;                if (imageview.getTag().equals(url)) {                    updateImageview(imageview, bitmap);                }                mImageCache.put(url, bitmap);            }        });    }    //部分代码省略,具体参考《六大设计原则之开闭原则》}

现在用户觉得内存缓存已经不能满足要求,还需要缓存到sd卡中。如果不用设计模式去实现,我们通
常的做法是:

1.实现一个可以用于sd卡缓存的类DiskCache
2.在ImageLoader中将ImageCache改为DiskCache

但是如果用户的需求再次改变呢?需要双缓存,我们又得改原来的代码,这就相当于ImageLoader
的实现依赖具体细节类ImageCache类或者DiskCache类,或者其他的,这不违反了上一篇的开闭
原则了吗?也违反了本节中的依赖倒置原则。
那么我们可以考虑下把这些具体细节共同的特性抽象出来,我们就可以依赖于这个规则去实现我们
的细节,其实就是依赖于抽象而不是细节。针对于图片缓存,主要是图片缓存的方式(内存、sd卡
或者双缓存),从缓存的地方取出图片这两个功能。暂且不考虑各缓存方式是怎么实现的,我们先
抽象出这两个共性。所以我们建一个图片缓存的接口:

public interface ImageCache {    void put(String url, Bitmap bitmap);    Bitmap get(String url);}

在接口中有两个方法,其中一个用于存,一个用于取。
这样ImageLoader类就可以通过注入的方式依赖于这个接口,如下所示

public class ImageLoader {    //内存缓存,依赖于抽象,并且有一个默认的缓存策略MemoryCache,MemoryCache类参考上一篇文章    private ImageCache mImageCache = new MemoryCache();    //线程池,线程数量为CUP的数量    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().            availableProcessors());    //UI Handler    Handler mUiHandler = new Handler(Looper.getMainLooper());    /**     * 提供外部调用显示图片的函数     *     * @param url       图片的路径     * @param imageview 显示图片的view     */    public void displayImage(final String url, final ImageView imageview) {        Bitmap bitmap = mImageCache.get(url);        if (bitmap != null) {            imageview.setImageBitmap(bitmap);            return;        }        imageview.setTag(url);        mExecutorService.submit(new Runnable() {            @Override            public void run() {                Bitmap bitmap = downloadImage(url);                if (bitmap == null) return;                if (imageview.getTag().equals(url)) {                    updateImageview(imageview, bitmap);                }                mImageCache.put(url, bitmap);            }        });    }    /**    *设置注入的缓存策略,依赖于对象    */    public void setImageCache(ImageCache cache){        mImageCache = cache;    }    //部分代码省略,具体参考《六大设计原则之开闭原则》}

最后,我们想用哪种缓存策略,只要实现接口ImageCache接口即可,然后通过ImageLoader
对象中的setImageCache()注入即可。这样我们就不需要去更改ImageLoader中的代码了。