美文网首页
面向对象基本原则 - 开闭原则

面向对象基本原则 - 开闭原则

作者: wenou | 来源:发表于2018-05-19 11:59 被阅读28次
开闭原则 - (让程序更稳定,更灵活)

上一篇:
面向对象基本原则 - 单一职责

开闭原则是java里最基础的设计原则
定义是:对象(类,模块,函数等)应该对于扩展是开放的,对于修改是封闭的

当需要对代码进行修改,这个时候应该尽量去扩展原来的代码,而不是去修改原来的代码,修改原来的代码就有可能会引起其他的问题

这里还是拿上一篇 单一职责 的例子来说明

由于之前的ImageLoader只有内存缓存
有一天,我们想要增加功能,给ImageLoader增加SD卡本地缓存,并且提供一个方法,让调用者来选择使用内存缓存还是本地缓存,于是代码就要修改了

添加本地缓存DiskCache类,这里只是学习基本原则,就不使用系统的DiskLruCache类了

public class DiskCache {
    private static final String cacheDir = "sdcard/cache";

    public Bitmap get(String imageUrl){
        return BitmapFactory.decodeFile(cacheDir + imageUrl);
    }

    public void put(String imageUrl,Bitmap bitmap){
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(cacheDir + imageUrl);
            bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

于是ImageLoader就修改成这样:

public class ImageLoader {

    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private ImageCache mImageCache = new ImageCache();
    private DiskCache mDiskCache = new DiskCache();

    private boolean isDiskCache;
    //对外提供方法设置,是否是本地缓存
    public void setDiskCache(boolean diskCache) {
        isDiskCache = diskCache;
    }

    public void displayImage(final String url, final ImageView imageView) {
        //判断是本地缓存还是内存缓存
        Bitmap bitmap = isDiskCache ? mDiskCache.get(url) : mImageCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        imageView.setTag(url);
        //没有缓存,提交到线程池下载
        submitLoad(url, imageView);
    }
    ...
}

代码看起来也还可以,但是如果有一天,我们希望内存和本地两种缓存都使用,如果内存缓存有就从内存里面取,内存没有再从本地里面取,本地也没有,再从网络上下载图片

修改代码,添加一个双缓存类DoubleCache

public class DoubleCache {
    private ImageCache mMemoryCache = new ImageCache();
    private DiskCache mDiskCache = new DiskCache();

    public Bitmap get(String url){
        Bitmap bitmap = mMemoryCache.get(url);
        if(bitmap == null){
            bitmap = mDiskCache.get(url);
            mMemoryCache.put(url,bitmap);
        }
        return bitmap;
    }
    public void put(String url,Bitmap bitmap){
        mMemoryCache.put(url,bitmap);
        mDiskCache.put(url,bitmap);
    }
}

然后ImageLoader也要修改判断了

public class ImageLoader {

    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private ImageCache mMemoryCache = new ImageCache();
    private DiskCache mDiskCache = new DiskCache();
    private DoubleCache mDoubleCache = new DoubleCache();

    private boolean isDiskCache;
    private boolean isDoubleCache;

    //对外提供方法设置,是否是本地缓存
    public void setDiskCache(boolean diskCache) {
        isDiskCache = diskCache;
    }
    //是否使用双重缓存
    public void setDoubleCache(boolean doubleCache) {
        isDoubleCache = doubleCache;
    }

    public void displayImage(final String url, final ImageView imageView) {
        //判断是本地缓存还是内存缓存
        Bitmap bitmap = null;
        if(isDoubleCache){
            bitmap = mDoubleCache.get(url);
        }else if(isDiskCache){
            bitmap = mDiskCache.get(url);
        }else {
            bitmap = mMemoryCache.get(url);
        }
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        imageView.setTag(url);
        //没有缓存,提交到线程池下载
        submitLoad(url, imageView);
    }
}

到这里就会发现,每次修改缓存功能的时候,都要修改ImageLoader类,然后通过一系列的判断来选择使用那种缓存,使得if-else越来越多,代码越来越复杂,如果不小心写错某个if判断,容易出现错误,也会让ImageLoader越来越臃肿,更重要的是,用户不能实现自己的缓存注入到ImageLoader中,可扩展性差

而开闭原则指明,对象(类,模块,函数等)应该对于扩展是开放的,对于修改是封闭的,所以这里应该重构ImageLoader的代码,使得结构更加清晰,稳定

结构图

抽象一个顶层接口,各种缓存来实现这个接口,统一管理

public interface ImageCache {
    Bitmap get(String url);
    void put(String url,Bitmap bitmap);
}
public class ImageLoader {

    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    //默认实现
    private ImageCache mImageCache = new MemoryCache();

    public void setImageCache(ImageCache cache){
        mImageCache = cache;
    }

    public void displayImage(final String url, final ImageView imageView) {
        Bitmap bitmap = mImageCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        imageView.setTag(url);
        //没有缓存,提交到线程池下载
        submitLoad(url, imageView);
    }
}

使用:

ImageLoader imageLoader = new ImageLoader();
//只使用内存缓存
imageLoader.setImageCache(new MemoryCache());
//只使用本地缓存
imageLoader.setImageCache(new DiskCache());
//使用双缓存
imageLoader.setImageCache(new DoubleCache());
//自定义缓存图片实现
imageLoader.setImageCache(new ImageCache() {
     @Override
     public Bitmap get(String url) {
          return null;
     }
     @Override
     public void put(String url, Bitmap bitmap) {
           //自定义缓存图片
      }
});

重构后的代码没有了那么多 if-else判断,少了各种各样的缓存对象实例,代码清晰简洁.ImageLoader变得更加稳定,扩展性和灵活性更高,当需要自定义缓存的时候,实现ImageCache接口就可以,并且通过setImageCache()方法注入到ImageLoader

遵循开闭原则的最重要的一点是抽象,用抽象去构建框架,用实现扩展细节;这样当发生修改的时候,直接实现抽象,派生一个类去实现不同的修改

下一篇:
面向对象基本原则 - 里氏替换 - 依赖倒置

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

相关文章

  • 面向对象基本原则 - 开闭原则

    开闭原则 - (让程序更稳定,更灵活) 上一篇:面向对象基本原则 - 单一职责 开闭原则是java里最基础的设计原...

  • 面向对象设计原则(二)开闭原则

    面向对象设计原则之开闭原则 开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。 开闭原则的...

  • 面向对象设计的六大基本原则

    面向对象设计的六大基本原则: 1)开闭原则 2)里氏代换原则 3)依赖倒转原则 4)接口隔离原则 5)迪米特法则 ...

  • Android 开发之SOLID原则

    SOLID是用来帮助定义面向对象设计五个基本原则的助记符: 单一功能原则 开闭原则 里氏替换原则 接口分离原则 依...

  • Java设计模式----工厂模式

    工厂模式实现了创建者和调用者的分离。 面向对象设计的基本原则: OCP(开闭原则,Open-Closed Prin...

  • 面向对象设计原则之开闭原则

    开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。开闭原则由Bertrand Meyer...

  • 《设计模式之蝉》 第五章 开闭原则

    开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。 开闭原则(Open-Closed Pr...

  • 面向对象的几大原则1

    一、开闭原则 是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。 定义:开闭原则(Open-Clo...

  • 01-设计模式原则

    面向对象的设计原则 面向对象的设计原则也被称为SOLID。SOLID原则包括单一职责原则、开闭原则、里氏替换原则、...

  • Swift设计模式----目录

    面向对象设计原则: 开闭原则 单一职责原则 依赖倒置原则 接口分离原则 迪米特法则 里氏替换原则 面向对象设计模式...

网友评论

      本文标题:面向对象基本原则 - 开闭原则

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