让程序更稳定、更灵活-----------开闭原则(学习笔记)

【一】定义:

         软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有的代码进行修改时,可能会将错误引入原本已经经过测试的旧代码中,破坏原有系统。因此当软件需要变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。当然,在现实开发中,只通过继承的方式来升级、维护原系统只是一个理想化的愿景,因此在实际的开发过程中,修改原有代码、扩展代码往往是同时存在的。

【二】例子

经过第一轮重构之后的ImageLoader职责单一、结构清晰,但新的需求来了,加入SD卡缓存。

于是有了下面的代码:

public class DiskCache {
    static String cacheDir = "sdcard/cache";
    //从缓存中获取图片 
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }
 //将图片缓存到内存中
    public void put(String url, Bitmap bitmap) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(cacheDir + url);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
}

因为需要将图片缓存到SD卡中,所以,ImageLoader代码有所更新,具体代码如下:


/**
*ImageLoader
**/
 
public class ImageLoader {
    //图片缓存
    ImageCache mImageCache = new ImageCache();

    //SD卡缓存
    DiskCache mDiskCache =new DiskCache();

    boolean isUseDiskCache = false;

    //线程池
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().
            availableProcessors());
 
    public void displayImage(final String url, final ImageView imageView){
        //判断使用哪种缓存
        Bitmap bitmap=isUseDiskCache?mDiskCache.get(url):mImageCache.get(url);
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
        return;
        }
        //没有缓存,则提交给线程池下载
        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 void useDiskCache(boolean useDiskCache){
        isUseDiskCache = useDiskCache;
     }
}

代码完成,但是有一个问题,不能同时使用SD卡缓存和内存缓存,最好的方案是优先使用内存缓存,如果内存缓存没有图片再使用SD卡缓存,如果SD中野没有图片最后才从网络上获取。因此又加入了一个双缓存类DoubleCache:

​
public class DoubleCache{
    ImageCache mMemoryCache =new ImageCache();
    DiskCache mDiskCache =new DiskCache();
    //先从缓存中获取图片,如果没有,再从SD卡中获取
    public Bitmap get(String url) {
        Bitmap bitmap=mMemoryCache(url);
        if(bitmap==null){
        bitmap = mDiskCache.get(url);
        }
        return bitmap ;
    }
 //将图片缓存到内存中
    public void put(String url, Bitmap bitmap) {
        mMemoryCache.put(url,bmp);
        mDiskCache.put(url,bmp);
    }
 
}

​

ImageLoader中的改动

​

/**
*ImageLoader
**/
 
public class ImageLoader {
    //图片缓存
    ImageCache mImageCache = new ImageCache();

    //SD卡缓存
    DiskCache mDiskCache =new DiskCache();

    //双缓存
    DoubleCache mDoubleCache =new DoubleCache();

    //使用双缓存
    boolean isUseDoubleCache=false;

    boolean isUseDiskCache = false;

    //线程池
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().
            availableProcessors());
 
    public void displayImage(final String url, final ImageView imageView){
        Bitmap bitmap=null;
        if(isUseDoubleCache){
          bitmap=mDoubleCache.get(url);
        }else if(isUseDiskCache ){
            bitmap=mDiskCache.get(url);
         }else{
            bitmap=mImageCache.get(url);
        }
        if (bitmap!=null){imageView.setImageBitmap(bitmap) return;}
        //没有缓存,则提交给线程池下载
        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 void useDiskCache(boolean useDiskCache){
        isUseDiskCache = useDiskCache;
     }
    public void useDoubleCache(boolean useDoubleCache){
        isUseDoubleCache = useDoubleCache;
     }
}

​

可以看到每次新增一个缓存方法都要修改Imageloader,这样很容易引入bug,而且会使原来的代码逻辑变得越来越复杂,而且也不能自定义缓存。

 软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。这就是开闭原则。

图:

代码如下:

/**
 * 缓存功能
 */
public interface ImageCache {
    public void put(String url, Bitmap bitmap);
    public Bitmap get(String url);
}
/**
 * 内存缓存
 */
public class MemeryCache implements ImageCache {
    private LruCache<String, Bitmap> mMemeryCache;
    public MemeryCache() {
        //最大内存
        int maxMemery = (int) (Runtime.getRuntime().maxMemory() / 1024);
        //取1/4 的可用内存作为缓存
        final int cacheSize = maxMemery / 4;
        mMemeryCache = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
    }
    @Override
    public void put(String url, Bitmap bitmap) {
        mMemeryCache.put(url,bitmap);
    }
    @Override
    public Bitmap get(String url) {
        return mMemeryCache.get(url);
    }
}
/**
 * sd卡存储
 */
public class DiskCache implements ImageCache {
    static String cacheDir = "sdcard/cache/";
    @Override
    public void put(String url, Bitmap bitmap) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(cacheDir + url);
            bitmap.compress(Bitmap.CompressFormat.PNG,100,fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }
}
/**
 * 双缓存
 */
public class DoubleCache implements ImageCache {
    ImageCache mMermeryCache = new MemeryCache();
    ImageCache mDisCache = new DiskCache();
    @Override
    public void put(String url, Bitmap bitmap) {
        mMermeryCache.put(url,bitmap);
        mDisCache.put(url,bitmap);
    }
    @Override
    public Bitmap get(String url) {
        Bitmap bitmap = mMermeryCache.get(url);
        if (bitmap == null){
            bitmap = mDisCache.get(url);
        }
        return bitmap;
    }
}
/**
 * imageView 通过url展示图片
 */
public class ImageLoader {
    ImageCache mImageCache = new MemeryCache();
    //线程池,线程数量为CPU数量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
 
    public void setImgeCache(ImageCache imgeCache){
        this.mImageCache = imgeCache;
    }
    public void displayImage(String url, ImageView imageView){
        Bitmap bitmap = mImageCache.get(url);
        if (bitmap != null){
            imageView.setImageBitmap(bitmap);
        }
        //没有缓存--下载
        submitLoadRequest(url,imageView);
 
    }
    private void submitLoadRequest(String imageUrl,ImageView imageView){
        imageView.setTag(imageUrl);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downLoadImage(imageUrl);
                if (bitmap == null){
                    return;
                }
                if (imageView.getTag().equals(imageUrl)){
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(imageUrl,bitmap);
            }
        });
    }
    public 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 imageLoader = new ImageLoader();
//设置缓存类型
imageLoader.setImgeCache(new DoubleCache());
//自定义缓存
imageLoader.setImgeCache(new ImageCache() {
       @Override
       public void put(String url, Bitmap bitmap) {
 
           }
 
            @Override
            public Bitmap get(String url) {
                return null;
            }
        });

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值