学习了何红辉、关爱民写的《Android设计模式》,对于面向对象的六大原则有进一步的理解,特此根据自己的理解记录总结一下
一个类、模块、函数等应该对于扩展是开放的,但是对于修改是封闭的,简单说就是当你的系统要升级维护需要对原有的代码进行修改时,可能会将错误引入到了原来的旧代码中,因此,在软件升级维护时,应该尽可能的通过扩展的方式而不是修改原有的代码,虽然在实际开发中,修改原本的代码跟扩展代码都是同时存在的,但是为了程序的可扩展性,在制作初期,应该遵循开闭原则。
以上一篇《面向对象的六大原则之 —— 单一原则》的例子为例继续讲解
在ImageCache类中,使用了内存缓存,可是内存缓存很有限,而且还容易丢失,比如应用关闭后,原来缓存在内存的图片会丢失,再打开需要重新加载,所以我们考虑加入SD卡缓存。
加入DiskCache类,缓存图片到SD卡中
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * Created by Administrator on 2016/3/1. */ public class DiskCache { public static final String cacheDir="sdcard/cache/"; /** * 获取sd卡的图片缓存 * @param url 图片url * @return 返回bitmap */ public Bitmap get(String url){ Bitmap bitmap=null; bitmap= BitmapFactory.decodeFile(cacheDir+url); return bitmap; } /** * 缓存到sd卡 * @param url 图片的url * @param bitmap bitmap对象 */ private void put(String url ,Bitmap bitmap){ FileOutputStream output = null; try { output = new FileOutputStream(cacheDir+url); bitmap.compress(Bitmap.CompressFormat.PNG,100,output); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { //无论是否有异常,都要关闭流 try { if(output!=null){ output.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.widget.ImageView; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2016/3/1. */ public class ImageLoader { public ImageLoader() { } //内存缓存类 ImageCache imageCache=new ImageCache(); //sd卡缓存类 DiskCache diskCache=new DiskCache(); //是否使用sd卡缓存 boolean isUseDiskCache=false; //线程池,线城数量为cpu的数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); /** * 显示图片 * @param url 图片的url * @param imageView 要显示的view */ public void displayImage(final String url, final ImageView imageView) { Bitmap bitmap=isUseDiskCache()?diskCache.get(url):imageCache.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)) { imageView.setImageBitmap(bitmap); } imageCache.put(url, bitmap); diskCache.put(url,bitmap); } }); } /** * 下載圖片 * @param imageUrl 网络图片地址 * @return 返回bitmap对象 */ public Bitmap downloadImage(String imageUrl) { Bitmap bitmap = null; try { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); bitmap = BitmapFactory.decodeStream(conn.getInputStream()); conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } public boolean isUseDiskCache() { return isUseDiskCache; } public void setIsUseDiskCache(boolean isUseDiskCache) { this.isUseDiskCache = isUseDiskCache; } }
import android.graphics.Bitmap; /** * Created by Administrator on 2016/3/1. */ public class DoubleCache { //内存缓存 ImageCache mImageCache=new ImageCache(); //sd卡缓存 DiskCache mDiskCache=new DiskCache(); /** * 获取缓存图片 * @param url 图片url * @return 返回bitmap对象 */ public Bitmap get(String url){ Bitmap bitmap=null; bitmap=mImageCache.get(url); if(bitmap==null){ bitmap=mDiskCache.get(url); } return bitmap; } /** * 缓存图片 * @param url 图片url * @param bitmap */ public void put(String url,Bitmap bitmap){ mImageCache.put(url,bitmap); mDiskCache.put(url,bitmap); } }
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.widget.ImageView; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2016/3/1. */ public class ImageLoader { public ImageLoader() { } //内存缓存类 ImageCache imageCache=new ImageCache(); //sd卡缓存类 DiskCache diskCache=new DiskCache(); //双缓存 DoubleCache doubleCache=new DoubleCache(); //是否使用sd卡缓存 boolean isUseDiskCache=false; //是否使用双缓存 boolean isUseDoubleCache=false; //线程池,线城数量为cpu的数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); /** * 显示图片 * @param url 图片的url * @param imageView 要显示的view */ public void displayImage(final String url, final ImageView imageView) { Bitmap bitmap=null; if(isUseDoubleCache()){ bitmap=doubleCache.get(url); }else if(isUseDiskCache()){ bitmap=diskCache.get(url); }else{ bitmap=imageCache.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)) { imageView.setImageBitmap(bitmap); } //缓存到内存跟sd卡中 doubleCache.put(url, bitmap); } }); } /** * 下載圖片 * @param imageUrl 网络图片地址 * @return 返回bitmap对象 */ public Bitmap downloadImage(String imageUrl) { Bitmap bitmap = null; try { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); bitmap = BitmapFactory.decodeStream(conn.getInputStream()); conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } public boolean isUseDiskCache() { return isUseDiskCache; } public void setIsUseDiskCache(boolean isUseDiskCache) { this.isUseDiskCache = isUseDiskCache; } public boolean isUseDoubleCache() { return isUseDoubleCache; } public void setIsUseDoubleCache(boolean isUseDoubleCache) { this.isUseDoubleCache = isUseDoubleCache; } }
ImageCache类如下:
import android.graphics.Bitmap; /** * Created by Administrator on 2016/3/1. */ public interface ImageCache { /** * 添加缓存 * @param url 缓存的图片url作为缓存的key * @param bitmap 缓存的bitmap */ public void put(String url, Bitmap bitmap); /** * 获取缓存的图片 * @param url * @return */ public Bitmap get(String url); }
所以,上面的内存缓存、sd卡缓存、双缓存三个类,我们全部修改实现ImageCache类
内存缓存类(MemoryCache)
import android.graphics.Bitmap; import android.util.LruCache; /** * Created by Administrator on 2016/3/1. */ public class MemoryCache implements ImageCache{ public MemoryCache() { //初始化图片缓存 initImageCache(); } //图片缓存类 LruCache<String, Bitmap> memoryCache; /** * 初始化缓存 */ private void initImageCache() { //计算可使用的最大内存 int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); //只用最大内存的四分之一作为缓存大小 int cacheSize = maxMemory / 4; memoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024; } }; } /** * 添加缓存 * * @param url 缓存的图片url作为缓存的key * @param bitmap 缓存的bitmap */ public void put(String url, Bitmap bitmap) { memoryCache.put(url, bitmap); } /** * 获取缓存的图片 * * @param url * @return */ public Bitmap get(String url) { Bitmap bitmap = null; bitmap = memoryCache.get(url); return bitmap; } }
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * Created by Administrator on 2016/3/1. */ public class DiskCache implements ImageCache{ public static final String cacheDir="sdcard/cache/"; /** * 获取sd卡的图片缓存 * @param url 图片url * @return 返回bitmap */ public Bitmap get(String url){ Bitmap bitmap=null; bitmap= BitmapFactory.decodeFile(cacheDir+url); return bitmap; } /** * 缓存到sd卡 * @param url 图片的url * @param bitmap bitmap对象 */ public void put(String url ,Bitmap bitmap){ FileOutputStream output = null; try { output = new FileOutputStream(cacheDir+url); bitmap.compress(Bitmap.CompressFormat.PNG,100,output); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { //无论是否有异常,都要关闭流 try { if(output!=null){ output.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
import android.graphics.Bitmap; /** * Created by Administrator on 2016/3/1. */ public class DoubleCache implements ImageCache{ //内存缓存 MemoryCache mMemoryCache =new MemoryCache(); //sd卡缓存 DiskCache mDiskCache=new DiskCache(); /** * 获取缓存图片 * @param url 图片url * @return 返回bitmap对象 */ public Bitmap get(String url){ Bitmap bitmap=null; bitmap= mMemoryCache.get(url); if(bitmap==null){ bitmap=mDiskCache.get(url); } return bitmap; } /** * 缓存图片 * @param url 图片url * @param bitmap */ public void put(String url,Bitmap bitmap){ mMemoryCache.put(url,bitmap); mDiskCache.put(url,bitmap); } }
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.widget.ImageView; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2016/3/1. */ public class ImageLoader { public ImageLoader() { } //默认使用内存缓存 ImageCache imageCache=new MemoryCache(); //线程池,线城数量为cpu的数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); /** * 设置要使用哪种缓存 * @param imageCache 缓存类 */ public void setImageCache(ImageCache imageCache) { this.imageCache = imageCache; } /** * 显示图片 * @param url 图片的url * @param imageView 要显示的view */ public void displayImage(final String url, final ImageView imageView) { Bitmap bitmap=imageCache.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)) { imageView.setImageBitmap(bitmap); } //添加到缓存 imageCache.put(url, bitmap); } }); } /** * 下載圖片 * @param imageUrl 网络图片地址 * @return 返回bitmap对象 */ public Bitmap downloadImage(String imageUrl) { Bitmap bitmap = null; try { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); bitmap = BitmapFactory.decodeStream(conn.getInputStream()); conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } }
<span style="white-space:pre"> </span>ImageLoader imageLoader=new ImageLoader(); /** * 内存缓存方式 */ imageLoader.setImageCache(new MemoryCache()); /** * SD卡缓存方式 */ imageLoader.setImageCache(new DiskCache()); /** * 双缓存方式 */ imageLoader.setImageCache(new DoubleCache()); /** * 自定义缓存方式 */ imageLoader.setImageCache(new ImageCache() { @Override public void put(String url, Bitmap bitmap) { //用户自定义的缓存方式 } @Override public Bitmap get(String url) { //从缓存中获取图片 return null; } });通过以上的修改,发现现在的ImageLoader的可扩展性、灵活性变的很高,三种缓存方式各自的具体实现都不一样,但是他们都实现了ImageCache接口,即有了这个标准,而用户想要自定义缓存实现的时候,只需要实现ImageCache接口,将其setImageCache进去即可。
以上就是开闭原则,对于修改是封闭的,对于扩展是开发的,遵循开闭原则的重要手段应该是通过抽象,由于实际开发中,可能会不尽人意,但是我们在设计的时候,应该尽量通过扩展的方式,这里说尽量是因为,可能原本的代码就是有问题的,必须要修改。
上一篇:《面向对象的六大原则之 —— 单一原则》
下一篇:《面向对象的六大原则之 —— 里氏替换原则》