面向对象深入解析Android

【 Android 进阶 】 专栏收录该内容
2 篇文章 0 订阅

目录

面向对象规范

图片加载示例

一:单一职责原则

二:开闭原则

三:里氏替换原则

四:依赖倒置原则

总结:


面向对象规范

面向对象的代码规范,需要有继承、封装、多态特点。具有单一职责原则(类中仅有相关性的封装)、开闭原则(更加稳定、灵活)、里氏替换原则(扩展性要好)、依赖倒置原则(拥有变化能力,可自定义类)、接口隔离原则(更高的灵活性)、迪米特原则(更好的扩展性)。

对于以上特点和原则,看着有点白话文的感觉,下面用图片加载示例来深入解析面向对象。

图片加载示例

需求:

写出一个具有缓存功能的图片展示封装类。

分析:

乍一看,功能蛮简单的,写一个ImageView布局,通过URL、HttpURLConnection把图片下载下来,在布局中显示不就行了,也就两行代码。好吧,这个思考是没错,因为这个可能是一个实习生写的Demo。

但是如果你脑子时刻想着面向对象的特点和原则,通过这些特点和原则来设计这个图片加载的功能那就完全不一样了。

一:单一职责原则

面向对象一个很重要的原则就是单一职责原则,一个类中应该把一组相关性很高的函数、数据封装起来(封装的特点),简单来说就是这个类的职责是什么,划分好职责就能确定类的功能了。

具体到图片加载项目中,把图片加载功能、图片缓存功能独立出来,让他满足单一职责原则。

先画一幅UML图

UML图分析直观明了,图片加载需要单独一个类,图片缓存需要单独一个类,各自封装自己的功能。两个完全不一样的功能,就不应该放在一个类中,开发者需要根据具体的业务、功能,对类进行相应的拆分,这个是重要的第一步。

ImageLoader图片加载类:

图片加载类包含:缓存调用、图片显示、图片下载,相关功能封装在一起。

/**
 * 图片加载类
 */
public class ImageLoader {
    //图片缓存
    ImageCache mImageCache = new MemoryCache();
    //线程池,线程数量为CPU的数量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //注入缓存实现
    public void setImageCache(ImageCache cache) {
        mImageCache = cache;
    }

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

    private void submitLoadRequest(final String imageUrl, final 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);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }
}

ImageCache图片缓存类,接口实现

缓存类包含: 缓存的写入、缓存的读取,相关功能封装在一起。这里使用接口,具体实现方式由子类实现。

/**
 * 图片缓存
 */
public interface ImageCache {
    Bitmap get(String url);
    void put(String url, Bitmap bitmap);
}


二:开闭原则

软件中的对象,对外扩展是开放的,但是对于外部的修改是封闭的。对于一个相对完整的类,如果想增加类的功能,尽量使用扩展的方式来实践,即继承的特点。通过继承的特点,来使你的类更稳定、更加的优秀。

对于一个大型的项目,某个父类的继承者非常多,可能达到十几个。十几个子类分别负责定制的功能,公共的特性在父类中实现,如果想增加一些定制的功能,只能继承父类,而不是修改父类,否则会导致项目整体出错。父类的角色就满足了对外扩展是开放的,对外修改是封闭的。

在图片加载项目中体现在图片缓存中。图片缓存可分为内存缓存、SD卡缓存、自定义缓存。那么怎么通过面向对象开闭原则,集成的特点来设计缓存呢?

1、缓存的存(put)、取(get)就是放在父类中。

2、子类1内存缓存、子类2 SD卡缓存、子类3双缓存(内存+SD卡)

3、自定义缓存,有些人引用的分装类,不想用以上两个缓存,想用自定义的缓存方式,所以你要能实现自定义缓存类的接入方式。

凡事先画UML图,直观明了:(画好的UML图,下载后尺寸就变形了)

对于ImageCache代码的继承实现,我们采用接口interface方式实现,不采用abstract抽象方式。(至于采用哪种方式,根据个人)。

ImageCache接口(父)

/**
 * 图片缓存
 */
public interface ImageCache {
    Bitmap get(String url);
    void put(String url, Bitmap bitmap);
}

MemoryCache内存缓存(子)

内存缓存使用LruCache方法,这里单独写了一篇博客做了详细解释其优势:Android LruCache缓存

/**
 * 内存缓存
 */
public class MemoryCache implements ImageCache {
    private LruCache<String, Bitmap> mMemeryCache;

    public MemoryCache() {
        //初始化LRU缓存
    }

    @Override
    public Bitmap get(String url) {
        return mMemeryCache.get(url);
    }

    @Override
    public void put(String url, Bitmap bitmap) {
        mMemeryCache.put(url, bitmap);
    }
}

DiskCache SD卡缓存(子)

实现方法比较多,可按照实际需求来做

/**
 * SD卡缓存
 */
public class DiskCache implements ImageCache{
    @Override
    public Bitmap get(String url) {
        return null; //从本地文件中获取图片
    }

    @Override
    public void put(String url, Bitmap bitmap) {
        //将Bitmap写入到文件中
    }
}

双缓存(子)

/**
 * 双缓存
 * 内存+SD卡
 */
public class DoubleCache implements ImageCache {
    ImageCache mMemoryCache = new MemoryCache();
    ImageCache mDiskCache = new DiskCache();

    //先从内存缓存中获取图片,如果没有,再从SD卡中获取
    public Bitmap get(String url) {
        Bitmap bitmap = mMemoryCache.get(url);
        if (bitmap == null) {
            bitmap = mDiskCache.get(url);
        }
        return bitmap;
    }

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

ImageLoader类中,增加了一个setImageCache的依赖注入方法,可以注入你的缓存实现:

private void test() {
        ImageLoader imageLoader = new ImageLoader();
        //使用内存缓存
        imageLoader.setImageCache(new MemoryCache());
        //使用SDka缓存
        imageLoader.setImageCache(new DiskCache());
        //使用双缓存
        imageLoader.setImageCache(new DoubleCache());
        //使用自定义的图片缓存实现
        imageLoader.setImageCache(new ImageCache() {
            
            @Override
            public void put(String url, Bitmap bmp) {
                //自定义缓存图片方式
            }

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

这里的setImageCache不仅可以注入已经定义好的三种缓存方式,还能实现自定义缓存方式,只需要你传入自己定义的子类即可。不仅能使ImageLoader更简单、健壮,也增加了ImageLoader的扩展性、灵活性。

三:里氏替换原则

面向对象语言的三大特点是继承、封装、多态,那么里氏替换就是依赖于继承、多态两大特性。

在图片缓存中,简单理解就是抽象。可以如下解释:

1、ImageCache封装了通用方法get和put。

2、各个子类实现接口方法,每个方法具体根据业务需求不同的实现方式,实现了集成、多态。

四:依赖倒置原则

依赖倒置原则规定了模块之间必须是解耦形式。

1、高层模块不应该依赖底层模块,两者都应该依赖其抽象;

2、抽象不应该依赖细节;

3、细节不应该依赖抽象;

通俗的讲:实例化new一个对象,不应该关心其实现方式,而是调用其高层模块,底层模块负责实现。调用缓存模块,只用setImageCache设置内存缓存、设置SD卡缓存就可以了,不用担心底层模块的实现方式。

总结:

在设计一个功能实现时候,脑子里面要时刻有面向对象的封装、继承、多态的特点,并根据几大原则来实现你的代码,你的代码才会有更好的扩展性,上传到你的github中,有了更好的扩展性,别人才能帮你扩展你的代码。在日常的项目中,后期增加不同的项目功能,才能在不影响成熟的功能同时,也能增加新的功能。


 

  • 0
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;"><span style="font-weight: bold;">技术简介:</span></p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;">Java高级特性涉及面向对象思想的核心内容,在Java体系中发挥着重要作用,设计模式、框架等也是建立在此基础之上。网络编程涉及Socket思想及相关API的使用,是网络应用的基础。输入/输出流是文件操作的基础,也是网络通信中数据传输的基础。线程技术在JavaEE应用及Android程序等开发领域运用广泛。</p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;"><span style="font-weight: bold;">课程适合人群:</span></p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;">本课程为Java入门课程,适合已经掌握了Java基础知识以及Java面向对象的人群学习。</p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;"><span style="font-weight: bold;">你将获得:</span></p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;">Java集合框架、泛型、Java实用类,I/O读写文本文件、多线程、Socket网络编程、XML解析等知识。</p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;">深入学习Java API中几个常用的核心类的用法。</p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;">Java高级API是所有Java高级开发的基础,只有熟练掌握Java SE的相关知识,梳理面向对象的思维方式,才能进入Java EE高级程序设计技术的学习。</p> <p style="font-size: 16px; color: #333333; font-family: 'Microsoft YaHei,SimHei,微软雅黑,黑体'; background-color: #ffffff;"><img src="https://img-bss.csdnimg.cn/202011040718296441.jpg" alt="" /><img src="https://img-bss.csdnimg.cn/202011040718449797.jpg" alt="" /></p>
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值