设计模式-6大设计原则

我对设计原则的理解:

使用注意项:

1.没有绝对符合

是否符合设计原则,是相对的程度值,而不是绝对的是非值!没有绝对符合或者绝对不符合,只有相对的符合多少!

2.不要过度设计

设计不足,可以重构!
设计过度,耗时耗力!

在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。
参考自:卡奴达摩的专栏

简单示例:

1.单一职责原则:

例:ImageLoader拆分成加载类和缓存类。

使用SRP之前:

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 作者:余天然 on 16/5/11 下午10:33
 */
public class ImageLoader {
    //图片缓存
    LruCache<String,Bitmap> cache;
    //线程池,线程数量为CPU的数量
    ExecutorService executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public ImageLoader() {
        init();
    }

    private void init() {
        //CPU最大可用内存
        final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
        //应用缓存
        final int cacheSize=maxMemory/4;
        cache=new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes()*bitmap.getHeight()/1024;
            }
        };
    }

    /**
     * 显示图片
     * @param url
     * @param imageView
     */
    public void displayImage(final String url, final ImageView imageView){
        imageView.setTag(url);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap=downloadImage(url);
                if(bitmap==null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    imageView.setImageBitmap(bitmap);
                }
                cache.put(url,bitmap);
            }
        });
    }

    /**
     * 下载图片
     * @param url
     * @return
     */
    private Bitmap downloadImage(String url) {
        try {
            HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection();
            Bitmap bitmap= BitmapFactory.decodeStream(connection.getInputStream());
            connection.disconnect();
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

使用SRP之后:

拆分成了ImageLoader和ImageCache,分别负责图片加载和图片缓存

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 作者:余天然 on 16/5/11 下午10:33
 */
public class ImageLoader {
    //图片缓存
    ImageCache cache=new ImageCache();
    //线程池,线程数量为CPU的数量
    ExecutorService executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    /**
     * 显示图片
     * @param url
     * @param imageView
     */
    public void displayImage(final String url, final ImageView imageView){
        imageView.setTag(url);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap=downloadImage(url);
                if(bitmap==null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    imageView.setImageBitmap(bitmap);
                }
                cache.put(url,bitmap);
            }
        });
    }

    /**
     * 下载图片
     * @param url
     * @return
     */
    private Bitmap downloadImage(String url) {
        try {
            HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection();
            Bitmap bitmap= BitmapFactory.decodeStream(connection.getInputStream());
            connection.disconnect();
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.util.LruCache;

/**
 * 作者:余天然 on 16/5/11 下午10:59
 */
public class ImageCache {
    //图片缓存
    LruCache<String,Bitmap> cache;

    public ImageCache() {
        init();
    }

    private void init() {
        //CPU最大可用内存
        final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
        //应用缓存
        final int cacheSize=maxMemory/4;
        cache=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){
        cache.put(url,bitmap);
    }

    public Bitmap get(String url){
        return cache.get(url);
    }

}

这就是单一职责原则,一个类尽量只做一组相关度很高的活。也就是类的方法之间是相关的,而不应该是正交的!

2.开闭原则:

例:ImageCache提取出公共接口。

使用OCP之前:

我们新增一个SD缓存类

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 这是简化版的,大家不要在意细节
 * 我懒得再写DiskLruCache了
 * 作者:余天然 on 16/5/11 下午11:16
 */
public class DiskCache {
    //图片缓存
    private static String cacheDir = "sdcard/cache/";

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

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

然后修改原有的ImageLoader,使其支持SD缓存类

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 作者:余天然 on 16/5/11 下午10:33
 */
public class ImageLoader {
    //内存缓存
    MemoryCache memoryCache = new MemoryCache();
    //SD卡缓存
    DiskCache diskCache = new DiskCache();
    //是否使用SDK缓存
    boolean isUseDiskCache = false;
    //线程池,线程数量为CPU的数量
    ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    /**
     * 显示图片
     *
     * @param url
     * @param imageView
     */
    public void displayImage(final String url, final ImageView imageView) {
        imageView.setTag(url);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                //判断从哪里获取图片(内存、SD卡、网络)
                Bitmap bitmap = isUseDiskCache ? diskCache.get(url) : memoryCache.get(url);
                if (bitmap == null) {
                    bitmap = downloadImage(url);
                }
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(url)) {
                    imageView.setImageBitmap(bitmap);
                }
                //添加到缓存
                memoryCache.put(url, bitmap);
                diskCache.put(url, bitmap);
            }
        });
    }

    /**
     * 下载图片
     *
     * @param url
     * @return
     */
    private Bitmap downloadImage(String url) {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
            connection.disconnect();
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean isUseDiskCache() {
        return isUseDiskCache;
    }

    public void setUseDiskCache(boolean useDiskCache) {
        isUseDiskCache = useDiskCache;
    }
}

显然,每添加一个缓存类就要修改加载类,这也太麻烦了!

使用OCP之后:

我们思考内存缓存和SD卡缓存的共性,抽象出一个接口:图片缓存接口

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;

/**
 * 图片缓存接口
 *
 * 作者:余天然 on 16/5/11 下午11:34
 */
public interface ImageCache {
    Bitmap get(String url);
    void put(String url, Bitmap bitmap);
}

然后将我们的加载类依赖于这个缓存接口,不再依赖于具体的缓存类

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 作者:余天然 on 16/5/11 下午10:33
 */
public class ImageLoader {
    //默认内存缓存,但声明的类型是接口
    ImageCache imageCache = new MemoryCache();
    //线程池,线程数量为CPU的数量
    ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    /**
     * 显示图片
     *
     * @param url
     * @param imageView
     */
    public void displayImage(final String url, final ImageView imageView) {
        imageView.setTag(url);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = imageCache.get(url);
                if (bitmap == null) {
                    bitmap = downloadImage(url);
                }
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(url)) {
                    imageView.setImageBitmap(bitmap);
                }
                //添加到缓存
                imageCache.put(url, bitmap);
            }
        });
    }

    /**
     * 下载图片
     *
     * @param url
     * @return
     */
    private Bitmap downloadImage(String url) {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
            connection.disconnect();
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public ImageCache getImageCache() {
        return imageCache;
    }

    public void setImageCache(ImageCache imageCache) {
        this.imageCache = imageCache;
    }
}

这样我们就可以实现各种各样的缓存类,而不必修改原有的加载类了

package com.che.carcheck.ui.test.design_pattern;

import android.graphics.Bitmap;

/**
 * 作者:余天然 on 16/5/11 下午11:40
 */
public class ImageLoaderTest {

    public static void main(String[] args) {
        ImageLoader imageLoader=new ImageLoader();
        //使用内存缓存
        imageLoader.setImageCache(new MemoryCache());
        //使用SD卡缓存
        imageLoader.setImageCache(new MemoryCache());
        //使用双缓存
        imageLoader.setImageCache(new MemoryCache());
        //使用自定义缓存
        imageLoader.setImageCache(new ImageCache() {
            @Override
            public Bitmap get(String url) {
                return null;
            }

            @Override
            public void put(String url, Bitmap bitmap) {

            }
        });
    }
}

3.里氏替换原则:

例:Window显示View。

4.接口隔离原则

例:关闭Closeable对象。

5.依赖倒置原则

例:ImageLoader依赖于抽象的ImageCache。

6.迪米特原则

例:中介找房。

里面的示例代码参考了:Android设计模式源码解析与实战


今天先写到这里,占好坑,以后再来完善下面的四个原则的示例

菜鸟一枚,水平有限,欢迎大家指出博文中的不足之处,小鱼将不胜感激!@qq:630709658

2016-10-20 10:497