我对设计原则的理解:
使用注意项:
1.没有绝对符合
是否符合设计原则,是相对的程度值,而不是绝对的是非值!没有绝对符合或者绝对不符合,只有相对的符合多少!
2.不要过度设计
设计不足,可以重构!
设计过度,耗时耗力!
在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。
参考自:卡奴达摩的专栏
简单示例:
1.单一职责原则:
例:ImageLoader拆分成加载类和缓存类。
使用SRP之前:
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.widget.ImageView;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 作者:余天然 on 16/5/11 下午10:33
*/
public class ImageLoader {
//图片缓存
LruCache<String,Bitmap> cache;
//线程池,线程数量为CPU的数量
ExecutorService executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public ImageLoader() {
init();
}
private void init() {
//CPU最大可用内存
final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
//应用缓存
final int cacheSize=maxMemory/4;
cache=new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes()*bitmap.getHeight()/1024;
}
};
}
/**
* 显示图片
* @param url
* @param imageView
*/
public void displayImage(final String url, final ImageView imageView){
imageView.setTag(url);
executorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap=downloadImage(url);
if(bitmap==null){
return;
}
if(imageView.getTag().equals(url)){
imageView.setImageBitmap(bitmap);
}
cache.put(url,bitmap);
}
});
}
/**
* 下载图片
* @param url
* @return
*/
private Bitmap downloadImage(String url) {
try {
HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection();
Bitmap bitmap= BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
使用SRP之后:
拆分成了ImageLoader和ImageCache,分别负责图片加载和图片缓存
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 作者:余天然 on 16/5/11 下午10:33
*/
public class ImageLoader {
//图片缓存
ImageCache cache=new ImageCache();
//线程池,线程数量为CPU的数量
ExecutorService executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/**
* 显示图片
* @param url
* @param imageView
*/
public void displayImage(final String url, final ImageView imageView){
imageView.setTag(url);
executorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap=downloadImage(url);
if(bitmap==null){
return;
}
if(imageView.getTag().equals(url)){
imageView.setImageBitmap(bitmap);
}
cache.put(url,bitmap);
}
});
}
/**
* 下载图片
* @param url
* @return
*/
private Bitmap downloadImage(String url) {
try {
HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection();
Bitmap bitmap= BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.util.LruCache;
/**
* 作者:余天然 on 16/5/11 下午10:59
*/
public class ImageCache {
//图片缓存
LruCache<String,Bitmap> cache;
public ImageCache() {
init();
}
private void init() {
//CPU最大可用内存
final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
//应用缓存
final int cacheSize=maxMemory/4;
cache=new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes()*bitmap.getHeight()/1024;
}
};
}
public void put(String url,Bitmap bitmap){
cache.put(url,bitmap);
}
public Bitmap get(String url){
return cache.get(url);
}
}
这就是单一职责原则,一个类尽量只做一组相关度很高的活。也就是类的方法之间是相关的,而不应该是正交的!
2.开闭原则:
例:ImageCache提取出公共接口。
使用OCP之前:
我们新增一个SD缓存类
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 这是简化版的,大家不要在意细节
* 我懒得再写DiskLruCache了
* 作者:余天然 on 16/5/11 下午11:16
*/
public class DiskCache {
//图片缓存
private static String cacheDir = "sdcard/cache/";
public void put(String url, Bitmap bitmap) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public Bitmap get(String url) {
return BitmapFactory.decodeFile(cacheDir + url);
}
}
然后修改原有的ImageLoader,使其支持SD缓存类
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 作者:余天然 on 16/5/11 下午10:33
*/
public class ImageLoader {
//内存缓存
MemoryCache memoryCache = new MemoryCache();
//SD卡缓存
DiskCache diskCache = new DiskCache();
//是否使用SDK缓存
boolean isUseDiskCache = false;
//线程池,线程数量为CPU的数量
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/**
* 显示图片
*
* @param url
* @param imageView
*/
public void displayImage(final String url, final ImageView imageView) {
imageView.setTag(url);
executorService.submit(new Runnable() {
@Override
public void run() {
//判断从哪里获取图片(内存、SD卡、网络)
Bitmap bitmap = isUseDiskCache ? diskCache.get(url) : memoryCache.get(url);
if (bitmap == null) {
bitmap = downloadImage(url);
}
if (bitmap == null) {
return;
}
if (imageView.getTag().equals(url)) {
imageView.setImageBitmap(bitmap);
}
//添加到缓存
memoryCache.put(url, bitmap);
diskCache.put(url, bitmap);
}
});
}
/**
* 下载图片
*
* @param url
* @return
*/
private Bitmap downloadImage(String url) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean isUseDiskCache() {
return isUseDiskCache;
}
public void setUseDiskCache(boolean useDiskCache) {
isUseDiskCache = useDiskCache;
}
}
显然,每添加一个缓存类就要修改加载类,这也太麻烦了!
使用OCP之后:
我们思考内存缓存和SD卡缓存的共性,抽象出一个接口:图片缓存接口
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
/**
* 图片缓存接口
*
* 作者:余天然 on 16/5/11 下午11:34
*/
public interface ImageCache {
Bitmap get(String url);
void put(String url, Bitmap bitmap);
}
然后将我们的加载类依赖于这个缓存接口,不再依赖于具体的缓存类
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 作者:余天然 on 16/5/11 下午10:33
*/
public class ImageLoader {
//默认内存缓存,但声明的类型是接口
ImageCache imageCache = new MemoryCache();
//线程池,线程数量为CPU的数量
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/**
* 显示图片
*
* @param url
* @param imageView
*/
public void displayImage(final String url, final ImageView imageView) {
imageView.setTag(url);
executorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap = imageCache.get(url);
if (bitmap == null) {
bitmap = downloadImage(url);
}
if (bitmap == null) {
return;
}
if (imageView.getTag().equals(url)) {
imageView.setImageBitmap(bitmap);
}
//添加到缓存
imageCache.put(url, bitmap);
}
});
}
/**
* 下载图片
*
* @param url
* @return
*/
private Bitmap downloadImage(String url) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ImageCache getImageCache() {
return imageCache;
}
public void setImageCache(ImageCache imageCache) {
this.imageCache = imageCache;
}
}
这样我们就可以实现各种各样的缓存类,而不必修改原有的加载类了
package com.che.carcheck.ui.test.design_pattern;
import android.graphics.Bitmap;
/**
* 作者:余天然 on 16/5/11 下午11:40
*/
public class ImageLoaderTest {
public static void main(String[] args) {
ImageLoader imageLoader=new ImageLoader();
//使用内存缓存
imageLoader.setImageCache(new MemoryCache());
//使用SD卡缓存
imageLoader.setImageCache(new MemoryCache());
//使用双缓存
imageLoader.setImageCache(new MemoryCache());
//使用自定义缓存
imageLoader.setImageCache(new ImageCache() {
@Override
public Bitmap get(String url) {
return null;
}
@Override
public void put(String url, Bitmap bitmap) {
}
});
}
}
3.里氏替换原则:
例:Window显示View。
4.接口隔离原则
例:关闭Closeable对象。
5.依赖倒置原则
例:ImageLoader依赖于抽象的ImageCache。
6.迪米特原则
例:中介找房。
里面的示例代码参考了:Android设计模式源码解析与实战
今天先写到这里,占好坑,以后再来完善下面的四个原则的示例
菜鸟一枚,水平有限,欢迎大家指出博文中的不足之处,小鱼将不胜感激!@qq:630709658