学习了何红辉、关爱民写的《Android设计模式》,对于面向对象的六大原则有进一步的理解,特此根据自己的理解记录总结一下
什么是里氏替换原则
面向对象的语言有三大特性:封装、继承、多态,里氏替换原则就是依赖于继承、多态这两大特性,它的原则就是只要父类能出现的地方子类就能出现,而且不会报错,但是子类能出现的地方,父类不一定能出现,术语就是 —— 抽象。
在上一篇《面向对象的六大原则之 —— 开闭原则》中我们说了要让程序可扩展,其实开闭原则跟里氏替换原则是不离不弃的,它们两个基本都是同时出现。
在上一篇中,ImageLoader类通过依靠ImageCache实现图片缓存,而ImageCache只是一个接口,真正的实现还需要通过实现ImageCache接口进行具体的业务逻辑的实现,比如内存缓存MemoryCache、sd卡缓存DiskCache、双缓存DoubleCache,而用户需要自定义实现缓存方式,可以通过实现ImageCache接口进行具体的实现,这让ImageLoader充满了无限的可能性。
在以上的逻辑中,其实已经很好的体现了里氏替换原则,我们想一下如果ImageLoader类中的setImageCache(ImageCache imageCache),这个imageCache不能够被子类替换的话,那用户如何设置不同的缓存对象, 也完全不能自定义实现缓存方式,通过《面向对象的六大原则之 —— 开闭原则》中的if{}()else()来判断使用什么样的缓存方式吗?
- /**
- * 显示图片
- * @param url 图片的url
- * @param imageView 要显示的view
- */
- public void displayImage(final String url, final ImageView imageView) {
- Bitmap bitmap=null;
- if(isUseDoubleCache()){
- bitmap=doubleCache.get(url);
- }else if(isUseDiskCache()){
- bitmap=diskCache.get(url);
- }else{
- bitmap=imageCache.get(url);
- }
这显然是不可行的,而里氏替换原则就是为这类问题提供指导原则,即建立抽象,通过抽象建立规范,我们的ImageCache用的是接口,其实是一样的,因为接口也是一种规范,我们通过实现了ImageCache接口达到不同的缓存策略,具体的实现在运行的时候进行设置:
- ImageLoader imageLoader=new ImageLoader();
- /**
- * 内存缓存方式
- */
- imageLoader.setImageCache(new MemoryCache());
- /**
- * SD卡缓存方式
- */
- imageLoader.setImageCache(new DiskCache());
- /**
- * 双缓存方式
- */
- imageLoader.setImageCache(new DoubleCache());
- /**
- * 自定义缓存方式
- */
- imageLoader.setImageCache(new ImageCache() {
- @Override
- public void put(String url, Bitmap bitmap) {
- //用户自定义的缓存方式
- }
- @Override
- public Bitmap get(String url) {
- //从缓存中获取图片
- return null;
- }
- });
所以,利用开闭原则跟里氏替换原则来达到对扩展开发,对修改封闭的效果,这两个原则都强调了一个OOP的重要特性——抽象,所以在开发中,灵活运用抽象,是让代码优化的重要一步。