美文网首页
单一职责原则

单一职责原则

作者: wuchao226 | 来源:发表于2019-04-25 15:27 被阅读0次

单一职责原则定义:就一个类而言,应该仅有一个引起它变化的原因。

  • 一个类/接口/方法只负责一项职责
  • 优点:降低类的浮复杂度、提高类的可读性、提高系统的可维护性、降低变更引起的风险。

下面以实现图片加载,并且要将图片缓存起来的的图片加载器(ImageLoader)为例进行介绍。

/**
 * 图片加载器
 */
public class ImageLoader {
    /**
     * 图片缓存
     */
    LruCache<String, Bitmap> mImageCache;
    /**
     * 线程池,线程数量为CPU数量
     * Runtime.getRuntime().availableProcessors() 方法:返回可用处理器的Java虚拟机的数量。
     */
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    /**
     * UI Handler
     */
    Handler mUiHandler = new Handler(Looper.getMainLooper());

    public 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) {
                //int size = bitmap.getRowBytes() * bitmap.getHeight();
                //获取大小,Bitmap所占用的内存空间数等于Bitmap的每一行所占用的空间数乘以Bitmap的行数
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    public void displayImage(final String url, final ImageView imageView) {
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(url)) {
                    updateImageView(imageView, bitmap);
                }
                mImageCache.put(url, bitmap);
            }
        });
    }

    private Bitmap downloadImage(String imageUrl) {
        Bitmap bitmap = null;
        try {
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    private void updateImageView(final ImageView imageView, Bitmap bitmap) {
        mUiHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bitmap);
            }
        });
    }
}

可以发现,ImageLoader 类中所有的功能都写在这一个类中,耦合严重,这样随着功能的增多,ImageLoader 类会越来越大,代码也越来越复杂,图片加载系统会越来越弱。

这时应把各个功能独立出来,让他们满足单一职责原则。

ImageLoader 代码修改如下:

/**
 * 图片加载器
 */
public class ImageLoader {
    /**
     * 图片缓存
     */
    ImageCache mImageCache;
    /**
     * 线程池,线程数量为CPU数量
     * Runtime.getRuntime().availableProcessors() 方法:返回可用处理器的Java虚拟机的数量。
     */
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    /**
     * UI Handler
     */
    Handler mUiHandler = new Handler(Looper.getMainLooper());

    /**
     * 加载图片
     */
    public void displayImage(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)) {
                    updateImageView(imageView, bitmap);
                }
                mImageCache.put(url, bitmap);
            }
        });
    }

    private Bitmap downloadImage(String imageUrl) {
        Bitmap bitmap = null;
        try {
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    private void updateImageView(final ImageView imageView, Bitmap bitmap) {
        mUiHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bitmap);
            }
        });
    }
}

并且添加了一个 ImageCache 类用于处理图片缓存,具体代码如下:

/**
 * 处理图片缓存
 */
public class ImageCache {
    /**
     * 图片LRU缓存
     */
    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) {
                //int size = bitmap.getRowBytes() * bitmap.getHeight();
                //获取大小,Bitmap所占用的内存空间数等于Bitmap的每一行所占用的空间数乘以Bitmap的行数
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    public void put(String url, Bitmap bitmap) {
        mImageCache.put(url, bitmap);
    }

    public Bitmap get(String url) {
        return mImageCache.get(url);
    }
}

如上述代码所示,将 ImageLoader 一拆为二,ImageLoader 只负责图片加载的逻辑,而 ImageCache 只负责处理图片缓存的逻辑,这样 ImageLoader 的代码量变少,职责也清晰;当与缓存相关的逻辑需要修改时,不需要修改 ImageLoader 类,而图片加载的逻辑需要修改时也不会影响到缓存处理逻辑。

上面的例子可以知道,单一职责所表达的就是“单一”。如何划分一个类,一个函数的职责,每个人都有自己的看法,它也有一些基本的指导原则,如,两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装。

相关文章

网友评论

      本文标题:单一职责原则

      本文链接:https://www.haomeiwen.com/subject/occngqtx.html