从ImageLoader来理解设计原则
2016-06-27 08:19
441 查看
本文整理自 android 源码设计模式
程序为了 高效 易读,对于 机器 和 人类 都有一个好的沟通.于是我们选择 中庸之道.这样对于机器来书,执行效率还比较高,对于人类理解来说,更易懂.
设计遵循的原则呢,根据人们在写代码的过程中,总结出来的经验,大的原则有六种.
单一职责 S
开闭原则O
里氏替换原则L
依赖倒置原则I
接口隔离D
迪米特(Least knowledge最少知识原则)
前5大原则正好缩写 SOLID—立体的 可靠的.有了这些原则可以说,程序就可靠了就靠谱了
加上第六大原则.第六大原则呢,是般若智慧,般若无知无所不知.
一切始于需求: 小二 来一份蛋炒饭,不要饭…
来一个 能缓存能下载图片的东东—
于是我们要去准备了,蛋和饭 本来看着在一个盘子里,可实际他们是两种不同的口味
我们要的东西首先能下载,其次还能缓存.这明明是两个要求好吗.两种口味(实际中,就算顾客要份炒饭,你也得问清楚,客官,你是要蛋炒饭还是要鸡蛋炒饭)
于是我们引出了我们第一个原则——-单一职责
我们写两个类—一个ImageLoader类,一个Cache类
第二次,顾客说,老板,蛋炒饭加点葱花!__开闭原则—一盘蛋炒饭得到了扩展———-可以除了主要的 蛋 和 饭 的原材料 功能外,我们可以根据自己口味 放 葱蒜青菜等—毕竟 可扩展是框架最重要的特性之一
那么开闭说的是什么呢?软件中的对象(类,模块,方法—)应该对于扩展是开放的,但,对于修改是封闭的.那么我们用什么方法来做到这一点呢?——抽象!
开闭原则 还有一个 孪生兄弟 叫做 里氏替换原则—所有引用基类的地方必须能透明的使用其子类的对象—说人话就是:只要父类能出现的地方,子类就能出现—-于是父类通常是个抽象的类或者接口(对于修改关闭)子类是具体的功能(对于扩展开放)
第四个原则,依赖倒置.在java中,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或者抽象类产生 的.
比如缓存,我们依赖于一个接口,而不是依赖于 具体的实现(比如硬盘缓存或是内存缓存)
第五,接口隔离原则—-目的解耦,更容易重构,更改和重新部署. 功能提供给用户,具体怎么实现,用户完全不知道!隔离实现类的细节,也使得我们将庞大的接口拆分到更细的粒度的接口中
第六 迪米特原则——只与直接的朋友通信.依赖的类少点,让自己变的更独立!
如果这些类都写在一个类中,对于以后的维护工作怎么做?为什么拆开呢?
更详细的可以看一下 书中 的精彩介绍android 源码设计模式
程序为了 高效 易读,对于 机器 和 人类 都有一个好的沟通.于是我们选择 中庸之道.这样对于机器来书,执行效率还比较高,对于人类理解来说,更易懂.
设计遵循的原则呢,根据人们在写代码的过程中,总结出来的经验,大的原则有六种.
单一职责 S
开闭原则O
里氏替换原则L
依赖倒置原则I
接口隔离D
迪米特(Least knowledge最少知识原则)
前5大原则正好缩写 SOLID—立体的 可靠的.有了这些原则可以说,程序就可靠了就靠谱了
加上第六大原则.第六大原则呢,是般若智慧,般若无知无所不知.
一切始于需求: 小二 来一份蛋炒饭,不要饭…
来一个 能缓存能下载图片的东东—
于是我们要去准备了,蛋和饭 本来看着在一个盘子里,可实际他们是两种不同的口味
我们要的东西首先能下载,其次还能缓存.这明明是两个要求好吗.两种口味(实际中,就算顾客要份炒饭,你也得问清楚,客官,你是要蛋炒饭还是要鸡蛋炒饭)
于是我们引出了我们第一个原则——-单一职责
我们写两个类—一个ImageLoader类,一个Cache类
第二次,顾客说,老板,蛋炒饭加点葱花!__开闭原则—一盘蛋炒饭得到了扩展———-可以除了主要的 蛋 和 饭 的原材料 功能外,我们可以根据自己口味 放 葱蒜青菜等—毕竟 可扩展是框架最重要的特性之一
那么开闭说的是什么呢?软件中的对象(类,模块,方法—)应该对于扩展是开放的,但,对于修改是封闭的.那么我们用什么方法来做到这一点呢?——抽象!
开闭原则 还有一个 孪生兄弟 叫做 里氏替换原则—所有引用基类的地方必须能透明的使用其子类的对象—说人话就是:只要父类能出现的地方,子类就能出现—-于是父类通常是个抽象的类或者接口(对于修改关闭)子类是具体的功能(对于扩展开放)
第四个原则,依赖倒置.在java中,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或者抽象类产生 的.
比如缓存,我们依赖于一个接口,而不是依赖于 具体的实现(比如硬盘缓存或是内存缓存)
第五,接口隔离原则—-目的解耦,更容易重构,更改和重新部署. 功能提供给用户,具体怎么实现,用户完全不知道!隔离实现类的细节,也使得我们将庞大的接口拆分到更细的粒度的接口中
第六 迪米特原则——只与直接的朋友通信.依赖的类少点,让自己变的更独立!
public interface ImageCache { public void put(String url, Bitmap bitmap); public Bitmap get(String url); }
public class ImageLoader { // 图片缓存 ImageCache mMemoryCache = new MemoryCache(); //线程池,线程数量为cpu的数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //注入缓存实现 public void setImageCache(ImageCache imageCache){ mMemoryCache = imageCache; Log.e("ImageLoader","setImageCache"); } public void displayImage(String imageUrl,ImageView imageView){ Bitmap bitmap = mMemoryCache.get(imageUrl); if (bitmap!=null){ imageView.setImageBitmap(bitmap); } //如果没缓存,提交到线程池下载图片 submitLoadRequest(imageUrl,imageView); } private void submitLoadRequest(final String imageUrl, final ImageView imageView) { imageView.setTag(imageUrl); Log.e("ImageLoader","submitLoadRequest"); mExecutorService.submit(new Runnable() { @Override public void run() { Log.e("ImageLoader", "submitLoadRequest2--"); Bitmap bitmap = downloadImage(imageUrl); if (bitmap == null) { return; } if (imageView.getTag().equals(imageUrl)) { imageView.setImageBitmap(bitmap); } mMemoryCache.put(imageUrl, bitmap); Log.e("ImageLoader", "submitLoadRequest"); } }); } /** * 这个耗时操作开一个线程去完成这个任务 * @param imageUrl * @return */ private Bitmap downloadImage(String imageUrl) { Bitmap bitmap = null; try { Log.e("ImageLoader","downloadImage1"); URL url = new URL(imageUrl); Log.e("ImageLoader","downloadImage2"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); Log.e("ImageLoader","downloadImage3"); bitmap = BitmapFactory.decodeStream(connection.getInputStream()); Log.e("ImageLoader","downloadImage"); connection.disconnect(); } catch (Exception e) { Log.e("ImageLoadereee",e.toString()); e.printStackTrace(); } return bitmap; } }
public class MemoryCache implements ImageCache { private LruCache<String ,Bitmap> mMemeryCache ; public MemoryCache(){ // // TODO: 2016/6/22 初始化Lru 缓存 initMemoryCache(); } /** * 自我感觉 这个类可以 也可以提供个接口给用户,让用户自己定义 */ private void initMemoryCache() { // 计算可使用的最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); //取 四分之一的可用内存作为缓存 final int cacheSize = maxMemory/4; mMemeryCache = new LruCache<String, Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes()*value.getHeight()/1024;//计算方式有两种 } }; } @Override public void put(String url, Bitmap bitmap) { mMemeryCache.put(url,bitmap); } @Override public Bitmap get(String url) { return mMemeryCache.get(url); } }
public class DoubleCache implements ImageCache { ImageCache mMemoryCache = new MemoryCache(); ImageCache mDiskCache = new DiskCache(); /* 将图片缓存到内存和sd卡中 */ @Override public void put(String url, Bitmap bitmap) { mMemoryCache.put(url, bitmap); mDiskCache.put(url, bitmap); } /* 先从内存中读取图片,如果没有,再从sd 卡中获取 */ @Override public Bitmap get(String url) { Bitmap bitmap = mMemoryCache.get(url); if (bitmap == null) { bitmap = mDiskCache.get(url); } return bitmap; } }
public class DiskCache implements ImageCache { @Override public void put(String url, Bitmap bitmap) { // 将bitmap 写入文件 } @Override public Bitmap get(String url) { return null;//从本地文件获取该图片 } }
如果这些类都写在一个类中,对于以后的维护工作怎么做?为什么拆开呢?
更详细的可以看一下 书中 的精彩介绍android 源码设计模式
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories