为了账号安全,请及时绑定邮箱和手机立即绑定

面向对象的六大设计原则(一)

标签:
设计

图片描述

一、单一职责:Single Responsibility Principle,简称SRP

定义:就一个类而言,应该只专注于做一件事和仅有一个引起它变化的原因。个人简单理解为:一个类只做它自己能做的事情,尽量低耦合,高类聚。通俗点讲就是各扫门前雪,你自己该干啥就干啥,不要去多管闲事,干好你自己的事情就行。

请看下面例子

/**
 * 图片加载类
 */
public class ImageLoader {
    // 图片缓存
    LruCache<String, Bitmap> mImageCache;
    // 线程池,线程数量为CPU的数量
    ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());

    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) {
                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)) {
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(url, bitmap);
          }
       });
    }

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

        return bitmap;
    }
}

这是没有遵循单一职责的代码,按照单一设计职责,当用户使用的是图片加载类时,只会关心图片加载这个功能,所以图片加载类应该只应该具备图片加载这个功能,然而代码中还加入的图片缓存的功能,这个不是用户所关心的问题。再者,这样的代码不利于后期维护和升级。接下来看看利用单一职责优化之后的代码。

/**
 * 图片加载类
 */
public  class ImageLoader {
    // 图片缓存
    ImageCache mImageCache = new ImageCache() ;
    // 线程池,线程数量为CPU的数量
    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);
            }
        });
     }

    public  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;
    }
}   

这个是图片缓存类

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) {
                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) ;
    }
}

经过这样处理,将共功能拆分之后,职责变得更清晰,更利于后期代码的维护和修改。

二、开闭原则:Open Close Principle,简称OCP

定义:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会将错误引入原本已经经过测试的旧代码中,破坏原有系统。

当时看到这个原则的时候,心里只有四个字,相见恨晚!想起了刚毕业找工作的时候被难住的面试题。题目大概意思是这样。需要做一个解析网络数据的工具类,在服务端返回的数据能拿到数据格式(xml,json,或者其他),根据数据格式进行相应的解析。当时也天真,这算什么面试题,那么简单,用if else 判断格式,再进行数据解析,是xml,接按xml 解析, 是json,就按json解析。当时也没多想,大笔一挥,就这样写了。

当时写的代码大概是这样

    public void analysisData(Mode type){
        if(type = xml){
            //进行xml 数据格式解析
        }else if(type = json){
            // 进行 json 数据格式解析
        }
    }

结果,当然是被pass掉了。现在我们来看看我当时写的代码,感觉是解决的题目所提出的问题,但是如果后期来了一种新的数据格式,代码就会变成这样

    public void analysisData(Mode type){
        if(type = xml){
            //进行xml 数据格式解析
        }else if(type = json){
            // 进行 json 数据格式解析
        }else if(type = 流文件){
            // 进行 数据流解析
        }else if(...type.) {
            //  
        }
    }

每次新加一种数据格式,就需要修改源码。不仅繁琐,而且一不留神,改错了判断语句,加错了括号,以前的代码也会跟着出现问题。维护起来相当繁琐,如果后期有100中数据格式,意味着要写一百次 if else 判断。记得当时,面试官问了一句,你觉得你的代码,可以再怎么优化一下, 我天真的说了句,可以用switch语句替换if else 汗颜 - - 。

我们回到开闭模式,看下如何用开闭模式优化如上代码

public class HttpUtils {

    AnalysisDate analysisData;

    public void analysisData(Mode type){
        analysisDate.analysis(type);
    }

    public void setAnalysisData(AnalysisData analysisDate){
        this.analysisDate = analysisDate;
    }

}   

/**
 * 解析数据接口
 *
 */
public interface  AnalysisData{
    void analysis(Mode type);
}

public class JsonAnalysisDate implements AnalysisData{

    public void analysis(Mode type) {
        // json 数据解析
    }
}
public class XmlAnalysisDate implements AnalysisData{

    public void analysis(Mode type) {
        // xml 数据解析
    }
}

怎么样? 是不是瞬间代码清理明了,后期如果新加了数据格式,只需要新建一个数据解析类 实现AnslysisData接口,不用修改以前的代码,维护起来使用起来都很方便。再也不不用写繁琐的if else 判断了

点击查看更多内容
64人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消