從程式碼規範提升程式設計能力
如果程式設計是你覺得有興趣的同學肯定會去挖掘更多底層實現原理及方法,如果你靠著程式設計養家餬口,你可能覺得工資不上漲是一個問題,不斷積累經驗及學習,希望掌握程式設計的奧祕,能夠換來更多酬勞;當然這是對的,也是做好的做法,是不是就從度娘搜尋最新最熱的知識,當然不是的,最新最熱門的並一定適合當下你做的工作,相關聯性也不一定很高,還是要從基礎及專業方面深挖,比如現在你是從事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開發的同學專案中的使用更多是封裝,但是若需要設計框架,對專案的重構還是需要去了解面向物件幾大原則有所瞭解,讓專案擴充套件性,靈活性,程式碼規範也是一個團隊良好的發展根基;
更多內容關注公眾號: