面向对象的六大原则

面向对象的六大原则:

单一职责原则、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特原则。

1、单一职责原则

英文名称:Single Responsibility Principle(SRP)

一个类应该具有单一的职责(职责可以理解为业务、功能)。

如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。

public class ImageLoader { //耦合了图片显示、图片内存缓存、图片下载功能
    //图片内存缓存
    LruCache mImageCache;
    //线程池
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public ImageLoader() {
        initImageCache();
    }

    //初始化
    private void initImageCache() {
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        //创建图片内存缓存对象
        mImageCache = new LruCache(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    //显示图片
    public void displayImage(final String url,final ImageView imageView) {
        //从内存缓存中获取图片
        Bitmap 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 class ImageLoader { //图片显示
    private ImageDownload mImageDownload;
    private ImageCache mImageCache;

    public ImageLoader() {
        mImageDownload = new ImageDownload();
        mImageCache = new ImageCache();
    }

    //显示图片
    public void displayImage(final String url,final ImageView imageView) {
        //从内存缓存中获取图片
        Bitmap bitmap = mImageCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        //下载图片
        mImageDownload.downloadImage(url, new ImageDownload.IDownload() {
            @Override
            public void onSuccess(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
                mImageCache.put(url, bitmap);
            }

            @Override
            public void onFail() {

            }
        });
    }
}

public class ImageDownload { //图片下载
    //线程池
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //下载图片
    public void downloadImage(final String imageUrl, final IDownload listener) {
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Bitmap bitmap;
                    URL url = new URL(imageUrl);
                    final HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                    bitmap = BitmapFactory.decodeStream(conn.getInputStream());
                    conn.disconnect();
                    if(bitmap != null) {
                        listener.onSuccess(bitmap);
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                listener.onFail();
            }
        });
    }

    public interface IDownload {
        void onSuccess(Bitmap bitmap);
        void onFail();
    }
}

public class ImageCache { //图片内存缓存
    //图片内存缓存
    LruCache mLruCache;

    public ImageCache() {
        initImageCache();
    }

    //初始化
    private void initImageCache() {
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        //创建图片内存缓存对象
        mLruCache = new LruCache(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    //从内存缓存中获取图片
    public Bitmap get(String url) {
        return mLruCache.get(url);
    }

    //将图片保存到内存缓存中
    public void put(String url, Bitmap bitmap) {
        mLruCache.put(url, bitmap);
    }
}

2、开闭原则

英文名称:Open Close Principle(OCP)

软件中的对象(类、模块、方法等)应该对于扩展是开放的,对于修改是封闭的。

面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。

在我们最初编写代码时,假设变化不会发生。当变化发生时,我们就创建抽象来隔离以后发生的同类变化。我们希望的是在开发工作展开不久就知道可能发生的变化。查明可能发生的变化所等待的时间越长,要创建正确的抽象就越困难。

开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。

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

    //从SD卡中获取图片
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }

    //将图片缓存到SD卡中
    @Override
    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 class ImageLoader {
    private ImageDownload mImageDownload;
    private ImageCache mImageCache;
    private DiskCache mDiskCache; //增加磁盘缓存变量
    private boolean mUseDiskCache; //增加是否使用磁盘缓存标记变量

    public ImageLoader() {
        mImageDownload = new ImageDownload();
        mImageCache = new ImageCache();
        mDiskCache = new DiskCache(); //创建磁盘缓存对象
    }

    //设置是否使用磁盘缓存
    public void setUseDiskCache(boolean useDiskCache) {
        mUseDiskCache = useDiskCache;
    }

    //显示图片
    public void displayImage(final String url,final ImageView imageView) {
        Bitmap bitmap;
        if(!mUseDiskCache) {
            bitmap = mImageCache.get(url); //从内存缓存中获取图片
        } else {
            bitmap = mDiskCache.get(url); //从磁盘缓存中获取图片
        }
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        //下载图片
        mImageDownload.downloadImage(url, new ImageDownload.IDownload() {
            @Override
            public void onSuccess(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
                if(!mUseDiskCache) {
                    mImageCache.put(url, bitmap); //将图片保存到内存缓存中
                } else {
                    mDiskCache.put(url, bitmap); //将图片保存到磁盘缓存中
                }
            }

            @Override
            public void onFail() {

            }
        });
    }
}

修改方案:

public interface ICache { //定义图片缓存接口
    Bitmap get(String url);
    void put(String url,Bitmap bitmap);
}

public class ImageCache implements ICache { //实现图片缓存接口
    //图片内存缓存
    LruCache mLruCache;

    public ImageCache() {
        initImageCache();
    }

    //初始化
    private void initImageCache() {
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;
        //创建图片内存缓存对象
        mLruCache = new LruCache(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    //从内存缓存中获取图片
    @Override
    public Bitmap get(String url) {
        return mLruCache.get(url);
    }

    //将图片保存到内存缓存中
    @Override
    public void put(String url, Bitmap bitmap) {
        mLruCache.put(url, bitmap);
    }
}

public class DiskCache implements ICache { //实现图片缓存接口
    private String cacheDir = "sdcard/cache/";

    //从SD卡中获取图片
    @Override
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }

    //将图片缓存到SD卡中
    @Override
    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 class ImageLoader {
    private ImageDownload mImageDownload;
    private ICache mCache; //图片缓存变量,接口类型

    public ImageLoader() {
        mImageDownload = new ImageDownload();
    }

    //设置图片缓存方式(可以是内存缓存,也可以是磁盘缓存)
    public void setCache(ICache cache) {
        mCache = cache;
    }

    //显示图片
    public void displayImage(final String url,final ImageView imageView) {
        Bitmap bitmap = mCache.get(url); //从缓存中获取图片(可以是内存缓存,也可以是磁盘缓存)
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        //下载图片
        mImageDownload.downloadImage(url, new ImageDownload.IDownload() {
            @Override
            public void onSuccess(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
                mCache.put(url, bitmap); //将图片保存到缓存中(可以是内存缓存,也可以是磁盘缓存)
            }

            @Override
            public void onFail() {

            }
        });
    }
}

3、里氏替换原则

英文名称:Liskov Substitution Principle(LSP)

所有引用基类的地方必须能透明地使用其子类的对象。

里氏替换原则的核心原理是抽象,抽象又依赖于继承这个特性。

建立抽象,通过抽象建立规范,具体的实现在运行时替换掉抽象,保证系统的扩展性、灵活性。开闭原则和里氏替换原则往往是生死相依、不弃不离的,通过里氏替换来达到对扩展开放,对修改关闭的效果。

代码参考:2、开闭原则
接口:ICache,实现类:ImageCache、DiskCache
在ImageLoader中引用的是接口:ICache,在运行时实现类:ImageCache、DiskCache会替换掉接口:ICache

4、依赖倒置原则

英文名称:Dependence Inversion Principle(DIP)

模块间的依赖通过抽象发生,其依赖关系是通过接口或抽象类产生的(面向接口编程或者说是面向抽象编程)。

依赖倒置原则有以下几个关键点:

(1)高层模块不应该依赖低层模块,两者都应该依赖其抽象;

(2)抽象不应该依赖细节;

(3)细节应该依赖抽象。

代码参考:2、开闭原则
接口:ICache,实现类:ImageCache、DiskCache
ImageLoader对ImageCache、DiskCache的依赖是通过接口ICache发生的

5、接口隔离原则

英文名称:Interface Segregation Principle(ISP)

类间的依赖关系应该建立在最小的接口上。

public class DiskCache implements ICache { //实现图片缓存接口
    private String cacheDir = "sdcard/cache/";

    //从SD卡中获取图片
    @Override
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }

    //将图片缓存到SD卡中
    @Override
    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 { //关闭IO流,代码可读性差
            if(fileOutPutStream!=null){
                try{
                    fileOutPutStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

修改方案:

public class CloseUtils {

    private CloseUtils() { }

    public static void closeIOQuietly(Closeable closeable) {
        if(closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

public class DiskCache implements ICache { //实现图片缓存接口
    private String cacheDir = "sdcard/cache/";

    //从SD卡中获取图片
    @Override
    public Bitmap get(String url) {
        return BitmapFactory.decodeFile(cacheDir + url);
    }

    //将图片缓存到SD卡中
    @Override
    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 { //关闭IO流,代码可读性好
            CloseUtils.closeIOQuietly(fileOutPutStream);
        }
    }
}

CloseUtils对FileOutputStream的依赖是建立在Closeable接口上的,该接口只定义了一个关闭IO流的方法:
public interface Closeable extends AutoCloseable {
    public void close() throws IOException;
}

6、迪米特原则(最少知识原则)

英文名称:Law of Demeter(LOD)

一个对象应该对其他对象有最少的了解。

一个类应该对自己需要耦合或调用的类知道得最少,类的内部如何实现与调用者或者依赖者没关系,调用者或者依赖者只需要知道它需要的方法即可,其他的可一概不用管。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

public class ImageLoader {
    private ImageDownload mImageDownload;
    private ICache mCache; //图片缓存变量,接口类型

    public ImageLoader() {
        mImageDownload = new ImageDownload();
    }

    //设置图片缓存方式(可以是内存缓存,也可以是磁盘缓存)
    public void setCache(ICache cache) {
        mCache = cache;
    }

    //显示图片
    public void displayImage(final String url,final ImageView imageView) {
        Bitmap bitmap = mCache.get(url); //从缓存中获取图片(可以是内存缓存,也可以是磁盘缓存)
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        //下载图片
        mImageDownload.downloadImage(url, new ImageDownload.IDownload() {
            @Override
            public void onSuccess(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
                mCache.put(url, bitmap); //将图片保存到缓存中(可以是内存缓存,也可以是磁盘缓存)
            }

            @Override
            public void onFail() {

            }
        });
    }
}

客户端只需要知道ImageLoader的setCache方法及displayImage方法即可,
至于图片缓存如何获取与保存、图片如何下载等都不需要知道。

你可能感兴趣的:(面向对象的六大原则)