从ImageLoader来理解设计原则

本文整理自 android 源码设计模式
程序为了 高效 易读,对于 机器 和 人类 都有一个好的沟通.于是我们选择 中庸之道.这样对于机器来书,执行效率还比较高,对于人类理解来说,更易懂.

设计遵循的原则呢,根据人们在写代码的过程中,总结出来的经验,大的原则有六种.

  1. 单一职责 S
  2. 开闭原则O
  3. 里氏替换原则L
  4. 依赖倒置原则I
  5. 接口隔离D
  6. 迪米特(Least knowledge最少知识原则)迪米特

    前5大原则正好缩写 SOLID—立体的 可靠的.有了这些原则可以说,程序就可靠了就靠谱了
    加上第六大原则.第六大原则呢,是般若智慧,般若无知无所不知.

一切始于需求: 小二 来一份蛋炒饭,不要饭…
来一个 能缓存能下载图片的东东—

于是我们要去准备了,蛋和饭 本来看着在一个盘子里,可实际他们是两种不同的口味
我们要的东西首先能下载,其次还能缓存.这明明是两个要求好吗.两种口味(实际中,就算顾客要份炒饭,你也得问清楚,客官,你是要蛋炒饭还是要鸡蛋炒饭)

于是我们引出了我们第一个原则——-单一职责
我们写两个类—一个ImageLoader类,一个Cache类

第二次,顾客说,老板,蛋炒饭加点葱花!__开闭原则—一盘蛋炒饭得到了扩展———-可以除了主要的 蛋 和 饭 的原材料 功能外,我们可以根据自己口味 放 葱蒜青菜等—毕竟 可扩展是框架最重要的特性之一
那么开闭说的是什么呢?软件中的对象(类,模块,方法—)应该对于扩展是开放的,但,对于修改是封闭的.那么我们用什么方法来做到这一点呢?——抽象!

开闭原则 还有一个 孪生兄弟 叫做 里氏替换原则—所有引用基类的地方必须能透明的使用其子类的对象—说人话就是:只要父类能出现的地方,子类就能出现—-于是父类通常是个抽象的类或者接口(对于修改关闭)子类是具体的功能(对于扩展开放)

第四个原则,依赖倒置.在java中,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或者抽象类产生 的.
比如缓存,我们依赖于一个接口,而不是依赖于 具体的实现(比如硬盘缓存或是内存缓存)

第五,接口隔离原则—-目的解耦,更容易重构,更改和重新部署. 功能提供给用户,具体怎么实现,用户完全不知道!隔离实现类的细节,也使得我们将庞大的接口拆分到更细的粒度的接口中

第六 迪米特原则——只与直接的朋友通信.依赖的类少点,让自己变的更独立!

工程结构

public interface ImageCache {
    public void put(String url, Bitmap bitmap);
    public Bitmap get(String url);
}
public class ImageLoader {
    // 图片缓存
    ImageCache  mMemoryCache = new MemoryCache();
    //线程池,线程数量为cpu的数量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //注入缓存实现
    public void setImageCache(ImageCache imageCache){
        mMemoryCache = imageCache;
        Log.e("ImageLoader","setImageCache");
    }

    public  void displayImage(String imageUrl,ImageView imageView){
        Bitmap bitmap = mMemoryCache.get(imageUrl);
        if (bitmap!=null){
            imageView.setImageBitmap(bitmap);
        }
        //如果没缓存,提交到线程池下载图片
        submitLoadRequest(imageUrl,imageView);

    }

    private void submitLoadRequest(final String imageUrl, final ImageView imageView) {
        imageView.setTag(imageUrl);
        Log.e("ImageLoader","submitLoadRequest");
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Log.e("ImageLoader", "submitLoadRequest2--");
                Bitmap bitmap = downloadImage(imageUrl);
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(imageUrl)) {
                    imageView.setImageBitmap(bitmap);
                }
                mMemoryCache.put(imageUrl, bitmap);
                Log.e("ImageLoader", "submitLoadRequest");
            }
        });
    }

    /**
     * 这个耗时操作开一个线程去完成这个任务
     * @param imageUrl
     * @return
     */
    private Bitmap downloadImage(String imageUrl) {
        Bitmap bitmap = null;
        try {
            Log.e("ImageLoader","downloadImage1");
            URL url = new URL(imageUrl);
            Log.e("ImageLoader","downloadImage2");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            Log.e("ImageLoader","downloadImage3");
            bitmap = BitmapFactory.decodeStream(connection.getInputStream());
            Log.e("ImageLoader","downloadImage");
            connection.disconnect();
        } catch (Exception e) {
            Log.e("ImageLoadereee",e.toString());
            e.printStackTrace();
        }

        return bitmap;
    }
}
public class MemoryCache implements ImageCache {

    private LruCache<String ,Bitmap> mMemeryCache ;
    public MemoryCache(){
        // // TODO: 2016/6/22 初始化Lru 缓存
        initMemoryCache();
    }

    /**
     * 自我感觉 这个类可以 也可以提供个接口给用户,让用户自己定义
     */
    private void initMemoryCache() {
        // 计算可使用的最大内存
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);

        //取 四分之一的可用内存作为缓存

        final int cacheSize = maxMemory/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);
    }
}
public class DoubleCache implements ImageCache {

    ImageCache mMemoryCache = new MemoryCache();
    ImageCache mDiskCache = new DiskCache();

    /*
    将图片缓存到内存和sd卡中
     */
    @Override
    public void put(String url, Bitmap bitmap) {
        mMemoryCache.put(url, bitmap);
        mDiskCache.put(url, bitmap);
    }

    /*
    先从内存中读取图片,如果没有,再从sd 卡中获取
     */
    @Override
    public Bitmap get(String url) {
        Bitmap bitmap = mMemoryCache.get(url);
        if (bitmap == null) {
            bitmap = mDiskCache.get(url);

        }
        return bitmap;
    }
}
public class DiskCache implements ImageCache {
    @Override
    public void put(String url, Bitmap bitmap) {
        // 将bitmap 写入文件
    }

    @Override
    public Bitmap get(String url) {
        return null;//从本地文件获取该图片
    }


}

如果这些类都写在一个类中,对于以后的维护工作怎么做?为什么拆开呢?

更详细的可以看一下 书中 的精彩介绍android 源码设计模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值