面向对象的六大原则之 —— 单一职责原则

时间:2022-04-06 15:08:31

学习了何红辉、关爱民写的《Android设计模式》,对于面向对象的六大原则有进一步的理解,特此根据自己的理解记录总结一下

在开发中,我们要注意程序设计的六大原则:

一、单一职责原则

二、开闭原则

三、里氏替换原则

四、依赖倒置原则

五、接口隔离原则

六、迪米特原则


什么是单一原则

单一原则的意思就是就一个类而言,它需要做的事情就一件,这一件事可以是拆分的很细的一件事(如:一台电脑,显示器就是显示用的,键盘就是打字用的,usb接口就是连接用的等等,有些人就把电脑整体理解成一台上网的机器,各有各的理解),单一原则的划分不是很清晰,一般都是看个人的理解来界定。

我们用一个简单图片加载器程序来说明单一原则的使用,需求是这样,我们要一个图片加载器,而且还能将图片缓存起来的,以此需求,我们写一个ImageLoader类

[java] view plain copy
  1. import android.graphics.Bitmap;  
  2. import android.graphics.BitmapFactory;  
  3. import android.util.LruCache;  
  4. import android.widget.ImageView;  
  5.   
  6. import java.io.IOException;  
  7. import java.net.HttpURLConnection;  
  8. import java.net.MalformedURLException;  
  9. import java.net.URL;  
  10. import java.util.concurrent.ExecutorService;  
  11. import java.util.concurrent.Executors;  
  12.   
  13. /** 
  14.  * Created by Administrator on 2016/3/1. 
  15.  */  
  16. public class ImageLoader {  
  17.   
  18.     public ImageLoader() {  
  19.         //初始化图片缓存  
  20.         initImageCache();  
  21.     }  
  22.   
  23.     //图片缓存类  
  24.     LruCache<String, Bitmap> imageCache;  
  25.     //线程池,线城数量为cpu的数量  
  26.     ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());  
  27.   
  28.     /** 
  29.      * 初始化缓存 
  30.      */  
  31.     private void initImageCache() {  
  32.         //计算可使用的最大内存  
  33.         int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
  34.         //只用最大内存的四分之一作为缓存大小  
  35.         int cacheSize = maxMemory / 4;  
  36.         imageCache = new LruCache<String, Bitmap>(cacheSize) {  
  37.             @Override  
  38.             protected int sizeOf(String key, Bitmap value) {  
  39.                 return value.getRowBytes() * value.getHeight() / 1024;  
  40.             }  
  41.         };  
  42.     }  
  43.   
  44.     /** 
  45.      * 显示图片 
  46.      * @param url 图片的url 
  47.      * @param imageView 要显示的view 
  48.      */  
  49.     public void displayImage(final String url, final ImageView imageView) {  
  50.         imageView.setTag(url);  
  51.         mExecutorService.submit(new Runnable() {  
  52.             @Override  
  53.             public void run() {  
  54.                 Bitmap bitmap = downloadImage(url);  
  55.                 if (bitmap == null) {  
  56.                     return;  
  57.                 }  
  58.                 if (imageView.getTag().equals(url)) {  
  59.                     imageView.setImageBitmap(bitmap);  
  60.                 }  
  61.                 imageCache.put(url, bitmap);  
  62.             }  
  63.         });  
  64.     }  
  65.     /** 
  66.      * 下載圖片 
  67.      * @param imageUrl 网络图片地址 
  68.      * @return 返回bitmap对象 
  69.      */  
  70.     public Bitmap downloadImage(String imageUrl) {  
  71.         Bitmap bitmap = null;  
  72.         try {  
  73.             URL url = new URL(imageUrl);  
  74.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  75.             bitmap = BitmapFactory.decodeStream(conn.getInputStream());  
  76.             conn.disconnect();  
  77.         } catch (MalformedURLException e) {  
  78.             e.printStackTrace();  
  79.         } catch (IOException e) {  
  80.             e.printStackTrace();  
  81.         }  
  82.         return bitmap;  
  83.     }  
  84. }  

可以看到,虽然上面的加载器已经实现了图片的加载以及缓存到内存的功能,但是有一个很明显的问题,所有东西都堆在了这个ImageLoader类里面了,耦合太严重,一点扩展性跟灵活性都没有,以后随着功能的增加,这个类会变的越来越大、臃肿,依照单一原则,把ImageLoader拆分一下,将功能独立出来

修改ImageLoader

[java] view plain copy
  1. import android.graphics.Bitmap;  
  2. import android.graphics.BitmapFactory;  
  3. import android.util.LruCache;  
  4. import android.widget.ImageView;  
  5.   
  6. import java.io.IOException;  
  7. import java.net.HttpURLConnection;  
  8. import java.net.MalformedURLException;  
  9. import java.net.URL;  
  10. import java.util.concurrent.ExecutorService;  
  11. import java.util.concurrent.Executors;  
  12.   
  13. /** 
  14.  * Created by Administrator on 2016/3/1. 
  15.  */  
  16. public class ImageLoader {  
  17.   
  18.     public ImageLoader() {  
  19.     }  
  20.   
  21.     //图片缓存类  
  22.     ImageCache imageCache=new ImageCache();  
  23.     //线程池,线城数量为cpu的数量  
  24.     ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());  
  25.   
  26.     /** 
  27.      * 显示图片 
  28.      * @param url 图片的url 
  29.      * @param imageView 要显示的view 
  30.      */  
  31.     public void displayImage(final String url, final ImageView imageView) {  
  32.         Bitmap bitmap=imageCache.get(url);  
  33.         if(bitmap!=null){  
  34.             imageView.setImageBitmap(bitmap);  
  35.             return;  
  36.         }  
  37.         imageView.setTag(url);  
  38.         mExecutorService.submit(new Runnable() {  
  39.             @Override  
  40.             public void run() {  
  41.                 Bitmap bitmap = downloadImage(url);  
  42.                 if (bitmap == null) {  
  43.                     return;  
  44.                 }  
  45.                 if (imageView.getTag().equals(url)) {  
  46.                     imageView.setImageBitmap(bitmap);  
  47.                 }  
  48.                 imageCache.put(url, bitmap);  
  49.             }  
  50.         });  
  51.     }  
  52.     /** 
  53.      * 下載圖片 
  54.      * @param imageUrl 网络图片地址 
  55.      * @return 返回bitmap对象 
  56.      */  
  57.     public Bitmap downloadImage(String imageUrl) {  
  58.         Bitmap bitmap = null;  
  59.         try {  
  60.             URL url = new URL(imageUrl);  
  61.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  62.             bitmap = BitmapFactory.decodeStream(conn.getInputStream());  
  63.             conn.disconnect();  
  64.         } catch (MalformedURLException e) {  
  65.             e.printStackTrace();  
  66.         } catch (IOException e) {  
  67.             e.printStackTrace();  
  68.         }  
  69.         return bitmap;  
  70.     }  
  71. }  


加入ImageCache.java


[java] view plain copy
  1. import android.graphics.Bitmap;  
  2. import android.util.LruCache;  
  3.   
  4. /** 
  5.  * Created by Administrator on 2016/3/1. 
  6.  */  
  7. public class ImageCache {  
  8.   
  9.     public ImageCache() {  
  10.         //初始化图片缓存  
  11.         initImageCache();  
  12.     }  
  13.   
  14.     //图片缓存类  
  15.     LruCache<String, Bitmap> imageCache;  
  16.   
  17.     /** 
  18.      * 初始化缓存 
  19.      */  
  20.     private void initImageCache() {  
  21.         //计算可使用的最大内存  
  22.         int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
  23.         //只用最大内存的四分之一作为缓存大小  
  24.         int cacheSize = maxMemory / 4;  
  25.         imageCache = new LruCache<String, Bitmap>(cacheSize) {  
  26.             @Override  
  27.             protected int sizeOf(String key, Bitmap value) {  
  28.                 return value.getRowBytes() * value.getHeight() / 1024;  
  29.             }  
  30.         };  
  31.     }  
  32.   
  33.     /** 
  34.      * 添加缓存 
  35.      * 
  36.      * @param url    缓存的图片url作为缓存的key 
  37.      * @param bitmap 缓存的bitmap 
  38.      */  
  39.     public void put(String url, Bitmap bitmap) {  
  40.         imageCache.put(url, bitmap);  
  41.     }  
  42.   
  43.     /** 
  44.      * 获取缓存的图片 
  45.      * 
  46.      * @param url 
  47.      * @return 
  48.      */  
  49.     public Bitmap get(String url) {  
  50.         Bitmap bitmap = null;  
  51.         bitmap = imageCache.get(url);  
  52.         return bitmap;  
  53.     }  
  54. }  

经过拆分之后,ImageLoader只负责图片的加载逻辑,而ImageCache负责图片的缓存逻辑,这样ImageLoader的代码量也就少了,而且职责也变的清晰,以后要修改缓存的逻辑就不需要去动ImageLoader类了,同样,修改图片加载的逻辑,也不需要动ImageCache类。

以上只是对单一原则的一个解释,因为单一原则不是定死的,每个人对一个职责的认定是不同的,这个要根据个人的经验以及具体的业务逻辑来定。