admin 发表于 2018-4-25 14:23:52

面向对象六大原则----单一职责原则

Java 中面向对象编程六大原则:单一职责原则 英文名称是Single Responsibility Principle,简称SRP开闭原则 英文全称是Open Close Principle,简称OCP里氏替换原则 英文全称是Liskov Substitution Principle,简称LSP依赖倒置原则英文全称是Dependence Inversion Principle,简称DIP
接口隔离原则 英文全称是InterfaceSegregation Principles,简称ISP
迪米特原则 英文全称为Law of Demeter,简称LOD,也称为最少知识原则(Least Knowledge Principle)


让你的代码更清晰简单——单一职责原则单一职责原则的英文名称是Single Responsibility Principle,简称SRP。它的定义是:就一个类而言,应该仅有一个引起它变化的原因。简单来说,一个类中应该是一组相关性很高的函数、数据的封装。单一职责的划分界限并不是总是那么清晰,很多时候都是需要靠个人经验来界定。当然,最大的问题就是对职责的定义,什么是类的职责,以及怎么划分类的职责。 下面以项目中实际代码来分析问题,在android app中图片加载是最常见的,于是我们自己动手写一个ImageLoader(图片加载)作为训练项目。如下代码:
view plain copy



[*]public class ImageLoader {
[*]    private static ImageLoader Instance = null;
[*]    // 图片缓存
[*]    LruCache<String, Bitmap> mImageCache;
[*]    // 线程池,线程数量为CPU的数量
[*]    ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());
[*]    //在主线程中显示图片
[*]    Handler mHandler = new Handler(){   
[*]      @Override
[*]      public void handleMessage(Message msg) {
[*]            super.handleMessage(msg);
[*]            ImageView imageView = (ImageView) msg.obj;
[*]            imageView.setImageBitmap((Bitmap) imageView.getTag());
[*]      }
[*]    };
[*]
[*]    public static ImageLoader getInstance(){
[*]      if(Instance == null){
[*]            synchronized (ImageLoader.class) {
[*]                if(Instance == null) {
[*]                  Instance = new ImageLoader();
[*]                }
[*]            }
[*]      }
[*]      return Instance;
[*]    }
[*]    private ImageLoader() {
[*]      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 bitmap) {
[*]                //Bitmap的每一行所占用的空间数乘以Bitmap的行数
[*]                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
[*]            }
[*]      };
[*]    }
[*]
[*]    publicvoid displayImage(final String url, final ImageView imageView) {
[*]      imageView.setTag(url);
[*]      //先从cache中取图片
[*]      if(mImageCache.get(url)!=null){
[*]            imageView.setImageBitmap(mImageCache.get(url));
[*]            return;
[*]      }
[*]      mExecutorService.submit(new Runnable() {
[*]            @Override
[*]            publicvoid run() {
[*]                Bitmap bitmap = downloadImage(url);
[*]                if (bitmap == null) {
[*]                  return;
[*]                }
[*]                if (imageView.getTag().equals(url)) {
[*]                  Message msg = mHandler.obtainMessage();
[*]                  imageView.setTag(bitmap);
[*]                  msg.obj = imageView;
[*]                  mHandler.sendMessage(msg);
[*]                }
[*]                mImageCache.put(url, bitmap);
[*]            }
[*]      });
[*]    }
[*]
[*]    publicBitmap downloadImage(String imageUrl) {
[*]      Bitmap bitmap = null;
[*]      try {
[*]            URL url = new URL(imageUrl);
[*]            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
[*]            conn.setDoInput(true); //允许输入流,即允许下载
[*]            conn.setUseCaches(false); //不使用缓冲
[*]            conn.setRequestMethod("GET"); //使用get请求
[*]            InputStream is = conn.getInputStream();   //获取输入流,此时才真正建立链接
[*]            bitmap = BitmapFactory.decodeStream(is);
[*]            conn.disconnect();
[*]      } catch (Exception e) {
[*]            e.printStackTrace();
[*]      }
[*]      return bitmap;
[*]    }
[*]}


上面是一个最简单的ImageLoader,在显示图片之前会去判断是否有缓存,但是我们也发现它耦合太严重啦!简直就没有设计可言,更不要说扩展性、灵活性了。所有的功能都写在一个类里,这样随着功能的增多,ImageLoader类会越来越大,代码也越来越复杂,修改起来就是进入hell.这里我们可以把ImageCahe相关的代码单独拿出来,写成一个单独的类。
view plain copy



[*]public class ImageCache {
[*]    // 图片缓存
[*]    LruCache<String, Bitmap> mImageCache;
[*]    public ImageCache(){
[*]      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 bitmap) {
[*]                //Bitmap的每一行所占用的空间数乘以Bitmap的行数
[*]                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
[*]            }
[*]      };
[*]    }
[*]      
[*]    public void put(String key,Bitmap value){
[*]      mImageCache.put(key,value);
[*]    }
[*]      
[*]    public Bitmap get(String key){
[*]       return mImageCache.get(key);
[*]    }
[*]}


所以ImageLoader代码需要修改,并且添加了一个ImageCache类用于处理图片缓存,具体代码如下:
view plain copy



[*]public class ImageLoader {
[*]    private static ImageLoader Instance = null;
[*]    private ImageCache mImageCache;
[*]    // 线程池,线程数量为CPU的数量
[*]    ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());
[*]    //在主线程中显示图片
[*]    Handler mHandler = new Handler(){
[*]      @Override
[*]      public void handleMessage(Message msg) {
[*]            super.handleMessage(msg);
[*]            ImageView imageView = (ImageView) msg.obj;
[*]            imageView.setImageBitmap((Bitmap) imageView.getTag());
[*]      }
[*]    };
[*]
[*]    public static ImageLoader getInstance(){
[*]      if(Instance == null){
[*]            synchronized (ImageLoader.class) {
[*]                if(Instance == null) {
[*]                  Instance = new ImageLoader();
[*]                }
[*]            }
[*]      }
[*]      return Instance;
[*]    }
[*]    private ImageLoader() {
[*]       mImageCache = new ImageCache();
[*]    }
[*]
[*]    publicvoid displayImage(final String url, final ImageView imageView) {
[*]      imageView.setTag(url);
[*]      //先从cache中取图片
[*]      if(mImageCache.get(url)!=null){
[*]            imageView.setImageBitmap(mImageCache.get(url));
[*]            return;
[*]      }
[*]      mExecutorService.submit(new Runnable() {
[*]            @Override
[*]            publicvoid run() {
[*]                Bitmap bitmap = downloadImage(url);
[*]                if (bitmap == null) {
[*]                  return;
[*]                }
[*]                if (imageView.getTag().equals(url)) {
[*]                  Message msg = mHandler.obtainMessage();
[*]                  imageView.setTag(bitmap);
[*]                  msg.obj = imageView;
[*]                  mHandler.sendMessage(msg);
[*]                }
[*]                mImageCache.put(url, bitmap);
[*]            }
[*]      });
[*]    }
[*]
[*]    publicBitmap downloadImage(String imageUrl) {
[*]      Bitmap bitmap = null;
[*]      try {
[*]            URL url = new URL(imageUrl);
[*]            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
[*]            conn.setDoInput(true); //允许输入流,即允许下载
[*]            conn.setUseCaches(false); //不使用缓冲
[*]            conn.setRequestMethod("GET"); //使用get请求
[*]            InputStream is = conn.getInputStream();   //获取输入流,此时才真正建立链接
[*]            bitmap = BitmapFactory.decodeStream(is);
[*]            conn.disconnect();
[*]      } catch (Exception e) {
[*]            e.printStackTrace();
[*]      }
[*]      return bitmap;
[*]    }
[*]}


和上述代码所示,将ImageLoader一拆为二,ImageLoader只负责图片加载的逻辑,而ImageCache只负责处理图片缓存的逻辑,这样ImageLoader的代码量变少了,职责也清晰了,当与缓存相关的逻辑需要改变时,不需要修改ImageLoader类,而图片加载的逻辑需要修改时也不会影响到缓存处理逻辑。从上述的例子中我们能够体会到,单一职责所表达出的用意就是“单一”二字。正如上文所说,如何划分一个类、一个函数的职责,每个人都有自己的看法,这需要根据个人经验、具体的业务逻辑而定。但是,它也有一些基本的指导原则,例如,两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装。工程师可以不断地审视自己的代码,根据具体的业务、功能对类进行相应的拆分。代码github地址:点击打开链接
更多精彩Android技术可以关注我们的微信公众号,扫一扫下方的二维码或搜索关注公共号: Android老鸟


来自:https://blog.csdn.net/jo__yang/article/details/52006982

页: [1]
查看完整版本: 面向对象六大原则----单一职责原则