@Tyhj
2018-07-13T08:55:54.000000Z
字数 5723
阅读 1273
设计模式
原文链接: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() {
@Override
public 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() {
@Override
public 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() {
@Override
public 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() {
@Override
public Bitmap get(String url) {
return null;
}
@Override
public void put(String url, Bitmap bmp) {
}
});
通过setImageCache(IamgeCache iamgeCache)方法注入不同的缓存实现,这样不仅能够使ImageLoader更简单、健壮,也使得Imageloader的灵活性、可扩展性更高。只需要新建一个实现ImageCache接口的类,注入到ImageLoader中,ImageLoader就可以实现各种各样的缓存策略,而且这些缓存策略不会导致ImageLoader类的修改。
用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。
该图片加载框架集成方法:
//Step 1. Add the JitPack repository to your build file
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
//Step 2. Add the dependency
dependencies {
implementation 'com.github.tyhjh:DesignMode:v1.3'
}
参考:《Android源码设计模式解析与实战》一书