美文网首页
单一职责原则

单一职责原则

作者: Tyhj | 来源:发表于2018-06-13 23:43 被阅读0次

    定义

    不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责

    问题由来

    类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。

    解决方案

    遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。

    即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,由于某种原因,也许是需求变更了,也许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

    举个栗子

    重构前代码

    public class ImageLoader {
    
        //图片缓存
        private LruCache<String, Bitmap> mImageCache;
    
        //线程池,线程数量为cpu的数量
        private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
        public ImageLoader() {
            initImageCache();
        }
    
        private void initImageCache() {
            //计算可使用的最大内存,进程能够拿到的最大内存
            int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
            //取四分之一作为缓存
            int cacheSize = maxMemory / 4;
            mImageCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                //重写sizeOf方法,计算出要缓存的每张图片的大小
                protected int sizeOf(String key, Bitmap bitmap) {
                    //Bitmap所占用的内存空间数等于Bitmap的每一行所占用的空间数乘以Bitmap的行数
                    return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
                }
            };
        }
    
        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);
                     imageView.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    })
                    mImageCache.put(url, bitmap);
                }
            });
        }
        
    
        public static Bitmap downLoadImage(String imageUrl) {
            Bitmap bitmap = null;
            try {
                URL url = new URL(imageUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                bitmap = BitmapFactory.decodeStream(connection.getInputStream());
                connection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap;
        }
    
    }
    

    LruCache

    LruCache是个泛型类,主要算法原理是把最近使用的对象用强引用(即我们平常使用的对象引用方式)存储在 LinkedHashMap 中。当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

    ExecutorService

    接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且可以让任务在后台执行。

    重构后代码:

    //缓存类
    public class ImageCache {
        //图片缓存
        private LruCache<String, Bitmap> mImageCache;
    
        public ImageCache(){
            initImageCache();
        }
    
        private void initImageCache() {
            //计算可使用的最大内存,进程能够拿到的最大内存
            final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
            //取四分之一作为缓存
            final int cacheSize = maxMemory / 4;
            //重写sizeOf方法,计算出要缓存的每张图片的大小
            mImageCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    //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);
        }
    
    }
    
    //图片加载类
    public class ImageLoader {
    
    
        ImageCache mImageCache = new ImageCache();
        //线程池,线程数量为cpu的数量
        private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
        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() {
                    final Bitmap bitmap = downLoadImage(url);
                    imageView.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    })
                    mImageCache.put(url, bitmap);
                }
            });
        }
    
        public static Bitmap downLoadImage(String imageUrl) {
            Bitmap bitmap = null;
            try {
                URL url = new URL(imageUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                bitmap = BitmapFactory.decodeStream(connection.getInputStream());
                connection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap;
        }
    
    }
    
    

    改变

    Imageloader只负责图片的加载,ImageCache只负责图片缓存的逻辑,Imageloader的代码量减少了,职责清晰了,缓存的逻辑需要改变的时候不影响缓存的处理逻辑,图片加载逻辑改变的时候也不会影响到缓存的逻辑。

    参考:《Android源码设计模式解析与实战》一书

    相关文章

      网友评论

          本文标题:单一职责原则

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