面向对象的单一职责原则

声明:本系列博客整理来源于《Android源码设计模式解析与实战》,仅作为个人学习总结记录,任何组织和个人不得转载进行商业活动!

 

单一职责原则(Simple Responsibility Priciple,SRP)

SRP的定义是:就一个类而言,应该仅有一个引起它变化的原因。简单来说,一个类中应该是一组相关性很高的函数、数据的封装。就像秦小波老师在《设计模式之禅》中说的:“这是一个备受争议却又极其重要的原则。只要你想和别人争执、怄气或者是吵架,这个原则是屡试不爽的”。因为单一职责的划分界限并不是总是那么清晰,很多时候都是需要靠个人经验来界定。当然,最大的问题就是对职责的定义,什么是类的职责,以及怎么划分职责。

对于计算机技术,通常只单纯的学习理论知识并不能很好的领会其深意,只有自己动手实践,并在实际运用中发现问题、解决问题、思考问题,才能够将知识吸收到自己的脑海中。Android是使用的面向对象设计开发的Java语言,程序中有抽象、接口、六大原则、23种设计模式等。在面向对象设计时,需考虑到其稳定性、可扩展性、灵活性。

毕业后刚开始做Android开发工作的小民同学,在经历过一周的适应期以及熟悉公司的产品、开发规范之后,开发工作正式开始。上级leader挑选了使用范围广、难度也适中的图片加载器ImageLoader,来作为一个小项目来锻炼小民的能力。leader的要求很简单,要小民实现图片加载,并且要将图片缓存起来。小民在分析了需求之后,就开始编码:

/**
 * 图片加载类
 */
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
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);

        //取1/4的可用内存作为缓存
        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 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)){
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }

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

        return bitmap;
    }
}

这时小民对图片加载ImageLoader任务完成,并且使用Git软件进行版本控制,将工程托管到GitHub上。给leader看后,说,“你的ImageLoader耦合太严重了。简直没有设计而言,更不要说扩展性、灵活性了。所有功能都写在一个类中怎么行呢,这样随着功能的增多,ImageLoader类会越来越大,代码也越来越复杂,图片加载系统就越来越脆弱......”小民听后,觉得之前匆忙想着完成任务,把任务想的太简单了。

“你还是把ImageLoader拆分一下,把各个功能独立出来,让它们满足单一职责原则。”leader最后说道。“单一职责原则”,小民敏锐的捕捉到关键词,经过上网查阅资料对它有一些认识,决定对ImageLoader进行一次重构。这次小民先画了一张ImageLoader实现的UML图,如下图所示:

ImageLoader修改如下:

/**
 * 图片加载类
 */
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
public class ImageLoader {
    private ImageCache mImageCache = new ImageCache();

    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() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null) return;
                if(imageView.getTag().equals(url)){
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }

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

        return bitmap;
    }
}

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

/**
 * 图片缓存类
 */
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
public class ImageCache {
    
    private LruCache<String,Bitmap> mImageCache;
    
    public ImageCache(){
        initImageCache();
    }

    private void initImageCache() {
        //计算可使用的最大内存
        int maxMemory = (int)(Runtime.getRuntime().maxMemory());

        //取1/4的可用内存作为缓存
        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 put(String url,Bitmap bitmap){
        mImageCache.put(url,bitmap);
    }

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

由上述的UML图和代码可看出,小民将ImageLoader一拆为二,ImageLoader只负责图片加载的逻辑,而ImageCache只负责处理图片缓存的逻辑,这样ImageLoader的代码量变少了,职责也清晰了;当与缓存相关的逻辑需要改变时,不需要修改ImageLoader类,而图片加载的逻辑需要修改时也不会影响到缓存处理的逻辑。虽然可扩展性还比较欠缺,但整个代码结构变得清晰许多,基本实现单一职责原则。

正如刚开始我们所说那样,如何划分一个类、一个函数的职责,每个人都有自己的看法,这需要根据个人经验、具体的业务逻辑而定。但是,它也有一些基本的指导原则,例如,两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装。工程师可以不断的审视自己的代码,根据具体的业务、功能对类进行相应的拆分,这是程序员优化代码迈出的第一步。

 

 

点击 - 面向对象的开闭原则>>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值