如何将Android数据库操作通用化(二)

概述

接着上回的说,虽然我们已经找出了阻挡我们通用化Android数据库操作的五个问题,但是现在我们还不能立即开始去解决这些问题。

试想一下,我们有一个News,那么,相应的就会有NewsDaoNewsDaoImpl,同理,如果出现一个Book,是不是也要写出BookDaoBookDaoImpl? 这个问题想想就觉得太疯狂!

这里的BookDao等等都是假想的,和NewsDao是一样的东西,就不在复制黏贴一遍了。(偷笑中….)

那么,在解决五个问题之前我们需要做的工作就是,把NewsDaoBookDao中公共的部分在提取一次;把NewsDaoImplBookDaoImpl中的公共部分也再提取一次。

去年一滴相思泪,今年刚流到腮边

工作需要一步一步做,那么我们首先抽取NewsDaoBookDao接口中公共的部分,并放在BaseDao中。既然是抽取公共的,那么原先位于NewsDao中,传入特定的参数(如:Integer、News)可能就不在适用了,我们需要寻找更为一般、通用的东西来替代,而泛型就是我们的好帮手(O(∩_∩)O~)。

public interface BaseDao<M> {
    /**
     * 增加
     */
    long insert(M m);

    /**
     * 删除<
     * 传入的参数可能或是Integer或者Long或者String,
     * 那么此处就不能够使用具有特殊性的类型,要使用具有一般性的、公共的。<
     * 而Serizlizable,则是Integer、Long、String共性的不二选择。
     */
    int delete(Serializable id);

    /**
     * 修改
     */
    int update(M m);

    /**
     * 查询所有
     */
    List<M> findAll();

}

是不是很简单?

我们把公用的方法抽取到BaseDao中,并把参数替换成为泛型和Serializable,这样NewsDao只需要继承我们的BaseDao并传入泛型,就大功告成了。代码如下:

public interface NewsDao extends BaseDao<News> {
    // 既然提取完公共的了,那么这些具有特殊性的就不需要了
    // 另外,实现BaseDao接口

    // long insert(News news);
    // int delete(int id);
    // int update(News news);
    // List<News> findAll();

    // 当然,除了通用的增删改查,还具有一些特有的方法
    // 比如,查询按时间排序的最新的新闻
}

是不是这个样子?NewsDao里面空空如也,当然,如果我们需要一些更为特殊的方法,还是需要写在这里面的,例如:查询按时间排序的最新的新闻。

问君能有几多愁?恰似一江春水向东流

既然接口中的公共的方法能够抽取,那么它们的实现类也是不能够例外的。我们抽取实现类(NewsDaoImplBookDaoImpl)中公共的部分,放在BaseDaoSupport中。

这里要记住BaseDaoBaseDaoSupport之间,只不过是NewsDaoNewsDaoImpl的映射,它们之间也是实现类的关系。

public abstract class BaseDaoSupport<M> implements BaseDao<M> {

    // * 抽取公共部分应该解决的问题:<br>
    // * 问题1:表名的获取<br>
    // * 问题2:如何将实体中的数据,按照对应关系导入到数据库中<br>
    // * 问题3:明确实体中主键是谁?获取到主键中封装的值<br>
    // * 问题4:实体的对象创建<br>
    // * 问题5:如何将数据库中表的列的数据,按照对应关系,封装到实体中<br>

    private Context context;
    private DBHelper helper;
    private SQLiteDatabase db;

    public BaseDaoSupport(Context context) {
        super();
        this.context = context;
        this.helper = new DBHelper(context);
        this.db = helper.getWritableDatabase();
    }

    @Override
    public long insert(M m) {
        // 请在此处填写代码
        return 0;
    }

    @Override
    public int delete(Serializable id) {
        // 请在此处填写代码
        return 0;
    }

    @Override
    public int update(M m) {
        // 请在此处填写代码
        return 0;
    }

    @Override
    public List<M> findAll() {
        // 请在此处填写代码
        return null;
    }

}

我们来看一下BaseDaoSupport中的东西,我们抽取出了ContextDBHelperSQLiteOpenHelper还有构造函数,看起来和我们的NewsDaoImpl中的东西一样。

再看看下面的insertdeleteupdatefindAll等方法,模子是一样的,只不过里面具体的参数替换成了泛型。

回过头我们看看被抽取完的NewsDaoImpl变成什么样子了,首先继承了BaseDaoSupport<News>并传入了自己所要操作的实体bean,然后又实现了NewsDao接口。代码如下:

public class NewsDaoImpl extends BaseDaoSupport<News> implements NewsDao {
    public NewsDaoImpl(Context context) {
        super(context);
    }
}

好像除了构造函数就空空如野了,但实际情况并非如此,我们在BaseDaoSupport中,已经实现了BaseBase接口,并且重写了insertupdatedeletefindAll等方法,这样我们NewsDaoImple中就继承了这些公共的方法了。

到了这一步是不是很开心! O(∩_∩)O~ ,代码看着越来越清爽了!

衣带渐宽终不悔,为伊消得人憔悴

到了这一步,我们的抽取和重构就基本完成了,那么我们接下来的工作重点就位于BaseDaoSupport,只要我们能够在此类中解决上一篇文章中碰到的五个问题,那么我们就可以做到Android中数据库的通用操作了。

是不是有点小激动了!! 别着急,我们慢慢来,请看下回分解!

最后把重构完成后的包结构展示给大家:

技术分享

技术分享

如果你浪费了自己的年龄,那是挺可悲的。因为你的青春只能持续一点儿时间——很短的一点儿时间。 —— 王尔德

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。