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

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(图片加载)作为训练项目。如下代码:

public class ImageLoader {
    private static ImageLoader Instance = null;
    // 图片缓存
    LruCache 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(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                //Bitmap的每一行所占用的空间数乘以Bitmap的行数
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

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

    public  Bitmap 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相关的代码单独拿出来,写成一个单独的类。

public class ImageCache {
    // 图片缓存
    LruCache mImageCache;
    public ImageCache(){
        initImageCache();
    }
    private void initImageCache() {
        // 计算可使用的最大内存
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        // 取四分之一的可用内存作为缓存
        final int cacheSize = maxMemory / 4;
        mImageCache = new LruCache(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类用于处理图片缓存,具体代码如下:

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

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

    public  Bitmap 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老鸟

                                                 面向对象六大原则----单一职责原则_第1张图片

你可能感兴趣的:(android系列)