如果编程是你觉得有兴趣的同学肯定会去挖掘更多底层实现原理及方法,如果你靠着编程养家糊口,你可能觉得工资不上涨是一个问题,不断积累经验及学习,希望掌握编程的奥秘,能够换来更多酬劳;当然这是对的,也是做好的做法,是不是就从度娘搜索最新最热的知识,当然不是的,最新最热门的并一定适合当下你做的工作,相关联性也不一定很高,还是要从基础及专业方面深挖,比如现在你是从事Android应用开发,你希望在应用开发能够体现自我价值,那就需要从Java面向对象思想,从代码规范提升自己的能力,学习源码的设计思路;我主要是起到抛砖引玉的作用,比较前辈后梁大神有很多;
一,面向对象的单一原则
一、单一职责原则,一个类应该仅有一个引起变化的原因,换句话来说,一个类中应该是一组相关性很高的函数、数据的封装;比如说在ImageLoader
public class ImageLoader { //内存缓存 ImageCache imageCache = new ImageCache(); //图片缓存 LruCache<String,Bitmap> mImageCache; //线程 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public ImageLoader(){ } private void initImageCache(){ //计算可使用最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); final int cacheSize = maxMemory / 4; mImageCache = new LruCache<String , Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes()* value.getHeight()/1024; } }; } public void displayImgae(final String url, final ImageView imageView){ Bitmap bitmap = mImageCache.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); } mImageCache.put(url,bitmap); } }); } public Bitmap downloadImage(String imageUrl){ Bitmap bitmap = null; try{ URL url = new URL(imageUrl); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); bitmap = BitmapFactory.decodeStream(connection.getInputStream()); connection.disconnect(); } catch (Exception e){ e.printStackTrace(); } return bitmap; } }
这段代码其实扩展性和灵活性都不好,缓存、下载、展示都在一个类里面,若需要考虑缓存图片的在本地,二级缓存或者三级缓存,代码可能在一个类里面会觉得很乱很杂;
可以把缓存抽出到一个类里面
public class ImageCache { //图片LRU缓存 LruCache<String,Bitmap> mImageCache; public ImageCache(){ initImageCache(); } private void initImageCache(){ //计算可使用的最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); final int cacheSzie= maxMemory/4; mImageCache = new LruCache<String, Bitmap>(cacheSzie){ @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight()/1024; } }; } public void put (String url,Bitmap bitmap){ mImageCache.put(url,bitmap); } public Bitmap get(String url){ return mImageCache.get(url); } }
二,怎么样让代码更灵活,扩展呢?开闭原则
在一本书上看到的概念,同事指导我们如何建立一个稳定的、灵活的系统,定义就是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,对于修改是封闭,软件开发过程中,最不会变化的就是变化本身,产品需要不断地升级,维护,产品需要升级,修改原来的代码就可能会引发其他的问题,那么,需要如何确保原有的软件模块的准确性,以及尽量少影响原有模块,当然是遵循开闭原则;
比如上面imageLoader 若需要缓存在本地
public class DiskCache { static String cacheDir = "sdcard/cache"; public Bitmap get(String url){ return BitmapFactory.decodeFile(cacheDir + url); } //将图片缓存到内存中 public void put (String url,Bitmap bmp){ FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(cacheDir + url); bmp.compress(Bitmap.CompressFormat.PNG,1 00,fileOutputStream); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { if (fileOutputStream != null){ try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
因为要缓存到SD卡 ,所以代码Imageloader代码也得更新
public class ImageLoader { //内存缓存 ImageCache imageCache = new ImageCache(); //sd卡缓存 DiskCache diskCache = new DiskCache(); //是否使用SD卡缓存 boolean isUseDisCache = false; //线程池 线程数量 ExecutorService mExecutorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors()); public void displayImgae(final String url, final ImageView imageView){ //判断本地是否有缓存 final Bitmap bitmap = isUseDisCache ?diskCache.g et(url): imageCache.get(url); if (bitmap!= null){ imageView.setImageBitmap(bitmap); return; } mExecutorService.submit(new Runnable() { @Override public void run() { if (bitmap!= null){ imageView.setImageBitmap(bitmap); return; } imageView.setTag(url); Bitmap bitmap = downloadImage(url); if (bitmap == null){ return; } if (imageView.getTag().equals(url)){ imageView.setImageBitmap(bitmap); } imageCache.put(url,bitmap); diskCache.put(url,bitmap); } }); } public void useDisCache(boolean isUseDisCache){ this.isUseDisCache = isUseDisCache; }
如果需要双缓存,代码还是需要改变,怎么样改有利后期的维护以及扩展,这就是开闭原则需要了解的。
public class DoubleCache { ImageCache mMemoryCache = new ImageCache(); DiskCache mDiskCache = new DiskCache(); //先从内存缓存中取出图片,没有在从SD卡 public Bitmap get(String url){ Bitmap bitmap = mMemoryCache.get(url); if (bitmap == null){ bitmap = mDiskCache.get(url); } return bitmap; } public void put (String url,Bitmap bitmap){ mMemoryCache.put(url,bitmap); mDiskCache.put(url,bitmap); } }
以上的代码还可以优化,可以把提取出一个图片缓存的接口,用来抽象缓存的功能
public interface ImageCache { public Bitmap get (String url); public void put (String url,Bitmap bitmap); } 其他缓存的方式不管是内存、本地、还是双缓存都可以实现该接口。 public class ImageLoader { //内存缓存 MemoryCache imageCache = new MemoryCache(); //是否使用SD卡缓存 boolean isUseDisCache = false; //是否使用双缓存 boolean isDoubleCache = false; private ImageCache mImageCahe; //线程池 线程数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public void setImageCache (ImageCache cache ){ mImageCahe = cache; } public void displayImgae(final String url, final ImageView imageView){ Bitmap bitmap = mImageCahe.get(url); if (bitmap!= null){ imageView.setImageBitmap(bitmap); return; }
public class MemoryCache extends ImageCache { //图片LRU缓存 LruCache<String,Bitmap> mImageCache; public MemoryCache(){ //初始化 initImageCache(); } private void initImageCache(){ //计算可使用的最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); final int cacheSize= maxMemory/4; mImageCache = 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){ mImageCache.put(url,bitmap); } @Override public Bitmap get(String url){ return mImageCache.get(url); } } public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageLoader imageLoader = new ImageLoader(); imageLoader.setImageCache((ImageCache) new MemoryCache()); imageLoader.setImageCache((ImageCache) new DiskCache()); imageLoader.setImageCache(new ImageCache() { @Override public Bitmap get(String url) { return null; } @Override public void put(String url, Bitmap bitmap) { } }); }
通过setImageCahe(ImageCache cache )方法缓存不同的地方,这样imageLoader更简单,直观,可扩展性要好很多,都可以实现ImageLoad接口,ImageLoad可以实现变幻莫测的需求,而不是每次都修改原有的代码。
三、总结
当然面向对象的特征封装、继承、多态;这个三个词语相信大家都不陌生,Java开发的同学可能比较深刻一些,Android开发的同学项目中的使用更多是封装,但是若需要设计框架,对项目的重构还是需要去了解面向对象几大原则有所了解,让项目扩展性,灵活性,代码规范也是一个团队良好的发展根基;