@Tyhj
        
        2018-07-13T00:55:54.000000Z
        字数 5723
        阅读 1498
    设计模式
原文链接:https://www.zybuluo.com/Tyhj/note/1192305
软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的
尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化
一个软件产品在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性。
在之前的图片加载框架,新增本地缓存功能,tag 1.2
public class DiskCache {//保存位置String cacheDir = "sdcard/cache/";//获取图片public Bitmap get(String url) {return BitmapFactory.decodeFile(cacheDir + url);}//保存图片到本地public void put(String url, Bitmap bitmap) {FileOutputStream fileOutputStream = null;fileOutputStream = new FileOutputStream(cacheDir + url);bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);}}
新增了图片缓存到SD卡中,所以ImageLoad代码有更新
public class ImageLoader {//内存缓存ImageCache mImageCache = new ImageCache();//SD卡缓存DiskCache mDiskCache = new DiskCache();//是否使用本地缓存boolean isUseDiskCache = false;public void setUseDiskCache(boolean useDiskCache) {isUseDiskCache = useDiskCache;}//线程池,线程数量为cpu的数量private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public void displayImage(final String url, final ImageView imageView, final Activity context) {final Bitmap bitmap = isUseDiskCache ? mDiskCache.get(url) : mImageCache.get(url);if (bitmap != null) {imageView.setImageBitmap(bitmap);return;}imageView.setTag(url);mExecutorService.submit(new Runnable() {@Overridepublic void run() {final Bitmap bitmap = downLoadImage(url);if (isUseDiskCache) {mDiskCache.put(url, bitmap);} else {mImageCache.put(url, bitmap);}imageView.setImageBitmap(bitmap);}});}public static Bitmap downLoadImage(String imageUrl) {Bitmap bitmap = null;URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();bitmap = BitmapFactory.decodeStream(connection.getInputStream());connection.disconnect();return bitmap;}}
代码完成,但是功能不是很合理,因为两种缓存不能同时使用,实际上,先从内存获取没有找到再从本地读取,本地也没有再从网络获取,才是最好的策略。
新增一个双重缓存的类
public class DoubleCache {ImageCache imageCache = new ImageCache();DiskCache diskCache = new DiskCache();/*** 双缓存,获取图片的时候先从内存中读取,如果没有再从SD卡中读取** @param url* @return*/public Bitmap get(String url) {Bitmap bitmap = imageCache.get(url);if (bitmap == null) {bitmap = diskCache.get(url);imageCache.put(url, bitmap);}return bitmap;}//将图片缓存到内存和SD卡中public void put(String url, Bitmap bitmap) {imageCache.put(url, bitmap);diskCache.put(url, bitmap);}}
再次修改ImageLoad代码
public class ImageLoader {//内存缓存ImageCache mImageCache = new ImageCache();//SD卡缓存DiskCache mDiskCache = new DiskCache();//双重缓存DoubleCache mDoubleCache = new DoubleCache();//是否使用本地缓存boolean isUseDiskCache = false;//双缓存boolean isUseDoubleCache = false;public void setUseDiskCache(boolean useDiskCache) {isUseDiskCache = useDiskCache;}public void setUseDoubleCache(boolean useDoubleCache) {isUseDoubleCache = useDoubleCache;}//线程池,线程数量为cpu的数量private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public void displayImage(final String url, final ImageView imageView, final Activity context) {Bitmap bitmap = null;if (isUseDoubleCache) {bitmap = mDoubleCache.get(url);} else if (isUseDiskCache) {bitmap = mDiskCache.get(url);} else {bitmap = mImageCache.get(url);}if (bitmap != null) {final Bitmap finalBitmap = bitmap;imageView.setImageBitmap(finalBitmap);return;}imageView.setTag(url);mExecutorService.submit(new Runnable() {@Overridepublic void run() {final Bitmap bitmap = downLoadImage(url);if (isUseDoubleCache) {mDoubleCache.put(url, bitmap);} else if (isUseDiskCache) {mDiskCache.put(url, bitmap);} else {mImageCache.put(url, bitmap);}imageView.setImageBitmap(bitmap);}});}public static Bitmap downLoadImage(String imageUrl) {Bitmap bitmap = null;try {URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();bitmap = BitmapFactory.decodeStream(connection.getInputStream());connection.disconnect();} catch (Exception e) {e.printStackTrace();}return bitmap;}}
双缓存完成了,但是存在一些问题,每次添加新功能的时候都要去修改ImageLoader源码,很可能引入bug,而且使得原来的代码越来越复杂、脆弱,不小心写错一个if条件就需要花费时间来排查,而且用户使用我们的框架,不能自己实现缓存注入到ImageLoader中,可扩展性差

开闭原则重构代码,ImageLoader
public class ImageLoader {//内存缓存ImageCache mImageCache = new MemoryCache();public void setmImageCache(ImageCache mImageCache) {this.mImageCache = mImageCache;}//线程池,线程数量为cpu的数量private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public void displayImage(final String url, final ImageView imageView, final Activity context) {Bitmap bitmap = mImageCache.get(url);if (bitmap != null) {final Bitmap finalBitmap = bitmap;imageView.setImageBitmap(finalBitmap);return;}imageView.setTag(url);mExecutorService.submit(new Runnable() {@Overridepublic void run() {final Bitmap bitmap = downLoadImage(url);mImageCache.put(url, bitmap);imageView.setImageBitmap(bitmap);}});}public static Bitmap downLoadImage(String imageUrl) {Bitmap bitmap = null;try {URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();bitmap = BitmapFactory.decodeStream(connection.getInputStream());connection.disconnect();} catch (Exception e) {e.printStackTrace();}return bitmap;}}
缓存继承ImageCache接口
public interface ImageCache {public Bitmap get(String url);public void put(String url, Bitmap bmp);}
使用方法:
//双重缓存imageLoader = new ImageLoader();imageLoader.setmImageCache(new DoubleCache());imageLoader.displayImage(url, iv_test1, this);//自定义缓存栗子imageLoader.setmImageCache(new ImageCache() {@Overridepublic Bitmap get(String url) {return null;}@Overridepublic void put(String url, Bitmap bmp) {}});
通过setImageCache(IamgeCache iamgeCache)方法注入不同的缓存实现,这样不仅能够使ImageLoader更简单、健壮,也使得Imageloader的灵活性、可扩展性更高。只需要新建一个实现ImageCache接口的类,注入到ImageLoader中,ImageLoader就可以实现各种各样的缓存策略,而且这些缓存策略不会导致ImageLoader类的修改。
用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。
该图片加载框架集成方法:
//Step 1. Add the JitPack repository to your build fileallprojects {repositories {...maven { url 'https://jitpack.io' }}}
//Step 2. Add the dependencydependencies {implementation 'com.github.tyhjh:DesignMode:v1.3'}
参考:《Android源码设计模式解析与实战》一书