当你对一门技术的入门知识都掌握的差不多了,常用的一些api已经很熟识之后,如果想提升你的代码质量,就必然需要引入一些设计模式的思想,或者是java中的面向对象思想,而面向对象中最重要的就是抽象类以及接口,这两个东西虽然学过java的人都认识,但是要真正用好并且深入理解的,如果没有经过一段时间的知识以及代码的积累很难体会。
下面先来简单介绍一下抽象类和接口:
1、抽象类是对一种事物的抽象,即对类抽象;而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为;但是接口确实对类局部(行为)进行抽象。
2、抽象类作为很多子类的父类,它是一种模版式设计;而接口是一种行为规范,是一种辐射式设计。
当我们发现我们的代码中有很多重复的地方,那么你就该优化你的代码了,提高你代码的扩展性以及移植性。
例如我们之前在写数据库时,拿greendao举例。
先通过greendao的实体类生成工具自动生成一个实体类
public class MainDaoGenerator {
public static final String SQL_DB="com.zx.greendaodemo.data.sql.db";
public static final String SQL_DAO="com.zx.greendaodemo.data.sql.dao";
public static void main(String[] args){
Schema schema = new Schema(1,SQL_DB);
schema.setDefaultJavaPackageDao(SQL_DAO);
createPerson(schema);
createStudent(schema);
try {
new DaoGenerator().generateAll(schema,getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
private static void createPerson(Schema schema){
Entity person = schema.addEntity("Person");
person.addIdProperty().primaryKey().autoincrement();
person.addStringProperty("name");
person.addIntProperty("age");
person.addStringProperty("sex");
person.implementsInterface("Parcelable");
}
private static void createStudent(Schema schema){
Entity student = schema.addEntity("Student");
student.addStringProperty("name").primaryKey();
student.addStringProperty("name_id");
student.addIntProperty("age");
student.implementsInterface("Parcelable");
}
/**
* 获取程序的根目录
*
* @return
*/
private static String getPath() {
String path=new StringBuilder()
.append("app")
.append(File.separator)
.append("src")
.append(File.separator)
.append("main")
.append(File.separator)
.append("java")
.append(File.separator).toString();
return new File(path).getAbsolutePath();
}
}
然后在我们的项目中一般情况下是这么写封装调用的,目前我有两个表,一个Person,一个Student,我需要分别写两个数据库操作帮助类,分别对这两个表中的数据进行操作。
public class PersonDBHelper {
private static final String DEFAULT_DATABASE_NAME = "greendao.db";
/**
* The Android Activity reference for access to DatabaseManager.
*/
private DaoMaster.DevOpenHelper mHelper;
private DaoSession daoSession;
private SQLiteDatabase database;
private DaoMaster daoMaster;
protected Context context;
protected String dbName;
public PersonDBHelper(Context context) {
this.context = context;
dbName = DEFAULT_DATABASE_NAME;
getmHelper(context, dbName);
}
public PersonDBHelper(Context context, String dbName) {
this.context = context;
this.dbName = dbName;
getmHelper(context, dbName);
}
public DaoMaster.DevOpenHelper getmHelper(Context context, String dbName) {
if (null == mHelper) {
mHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
return mHelper;
}
protected void openWritableDb() {
getWritableDatabase();
getDaoMaster();
getDaoSession();
}
protected SQLiteDatabase getWritableDatabase() {
database = getmHelper(context, dbName).getWritableDatabase();
return database;
}
protected DaoMaster getDaoMaster() {
if (null == daoMaster) {
daoMaster = new DaoMaster(getWritableDatabase());
}
return daoMaster;
}
protected DaoSession getDaoSession() {
if (null == daoSession) {
daoSession = getDaoMaster().newSession();
}
return daoSession;
}
public void closeDbConnections() {
if (null == mHelper) {
mHelper.close();
mHelper = null;
}
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
public void clearDaoSession() {
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
public void insert(Person p){
daoSession.getPersonDao().insert(p);
}
public List<Person> loadAll(){
return daoSession.getPersonDao().loadAll();
}
public void deleteAll(){
daoSession.getPersonDao().deleteAll();
}
}
public class StudentDBHelper {
private static final String DEFAULT_DATABASE_NAME = "greendao.db";
/**
* The Android Activity reference for access to DatabaseManager.
*/
private DaoMaster.DevOpenHelper mHelper;
private DaoSession daoSession;
private SQLiteDatabase database;
private DaoMaster daoMaster;
protected Context context;
protected String dbName;
public StudentDBHelper(Context context) {
this.context = context;
dbName = DEFAULT_DATABASE_NAME;
getmHelper(context, dbName);
}
public StudentDBHelper(Context context, String dbName) {
this.context = context;
this.dbName = dbName;
getmHelper(context, dbName);
}
public DaoMaster.DevOpenHelper getmHelper(Context context, String dbName) {
if (null == mHelper) {
mHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
return mHelper;
}
protected void openWritableDb() {
getWritableDatabase();
getDaoMaster();
getDaoSession();
}
protected SQLiteDatabase getWritableDatabase() {
database = getmHelper(context, dbName).getWritableDatabase();
return database;
}
protected DaoMaster getDaoMaster() {
if (null == daoMaster) {
daoMaster = new DaoMaster(getWritableDatabase());
}
return daoMaster;
}
protected DaoSession getDaoSession() {
if (null == daoSession) {
daoSession = getDaoMaster().newSession();
}
return daoSession;
}
public void closeDbConnections() {
if (null == mHelper) {
mHelper.close();
mHelper = null;
}
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
public void clearDaoSession() {
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
public void insert(Student s) {
daoSession.getStudentDao().insert(s);
}
public List<Student> loadAll() {
return daoSession.getStudentDao().loadAll();
}
public void deleteAll() {
daoSession.getStudentDao().deleteAll();
}
}
通过上面的这两个表的操作类的代码就会发现有很多重复的工作,而且当我们的表越多时冗余代码就越多,所以这时候就得想想我们怎么样利用我们以前学的抽象类、接口来解决这类问题?
现在可以回过头想想我们之前讲的抽象类和接口,抽象类是对一种事物的抽象,而接口是对行为的抽象。
联系我们上面的代码,我们所有的表都可以看成是一类事物,而对表的一些列操作我们可以看成是一系列行为,这样一分我们就应该得出一个简单的结构。
由图可以看出我们所有的表的操作都放在的IDatabase类中,让所有表中的基类去实现这个接口,而Person、Student表子类只需要去实现getAbstractDao方法就可以了,在IDatabase中的getAbstractDao方法采用了范型的方式,用的时候只要告诉你的实体类类型以及该表中的主键类型是什么就可以。
这样一来妈妈再也不用担心程序中会有多少个表了,so easy!
下面是三个类中的全代码:
public interface IDatabase<M,K> {
boolean insert(M m);
boolean add(M m);
List<M> loadAll();
/**
* 自定义查询
*
* @return
*/
QueryBuilder<M> getQueryBuilder();
/**
* @param where
* @param selectionArg
* @return
*/
List<M> queryRaw(String where, String... selectionArg);
boolean deleteAll();
AbstractDao<M, K> getAbstractDao();
}
public abstract class DatabaseManager<M, K> implements IDatabase<M, K> {
private static final String DEFAULT_DATABASE_NAME = "greendao.db";
/**
* The Android Activity reference for access to DatabaseManager.
*/
private DaoMaster.DevOpenHelper mHelper;
private DaoSession daoSession;
private SQLiteDatabase database;
private DaoMaster daoMaster;
protected Context context;
protected String dbName;
public DatabaseManager(Context context) {
this.context = context;
dbName = DEFAULT_DATABASE_NAME;
getmHelper(context, dbName);
}
public DatabaseManager(Context context, String dbName) {
this.context = context;
this.dbName = dbName;
getmHelper(context, dbName);
}
public DaoMaster.DevOpenHelper getmHelper(Context context, String dbName) {
if (null == mHelper) {
mHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
return mHelper;
}
protected void openWritableDb() {
getWritableDatabase();
getDaoMaster();
getDaoSession();
}
protected SQLiteDatabase getWritableDatabase() {
database = getmHelper(context, dbName).getWritableDatabase();
return database;
}
protected DaoMaster getDaoMaster() {
if (null == daoMaster) {
daoMaster = new DaoMaster(getWritableDatabase());
}
return daoMaster;
}
protected DaoSession getDaoSession() {
if (null == daoSession) {
daoSession = getDaoMaster().newSession();
}
return daoSession;
}
public void closeDbConnections() {
if (null == mHelper) {
mHelper.close();
mHelper = null;
}
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
public void clearDaoSession() {
if (null == daoSession) {
daoSession.clear();
daoSession = null;
}
}
@Override
public boolean insert(M m) {
if (null == m){
return false;
}
openWritableDb();
getAbstractDao().insert(m);
return true;
}
@Override
public boolean add(M m) {
if (null == m){
return false;
}
openWritableDb();
getAbstractDao().insert(m);
return true;
}
@Override
public List<M> loadAll() {
openWritableDb();
return getAbstractDao().loadAll();
}
@Override
public boolean deleteAll() {
openWritableDb();
getAbstractDao().deleteAll();
return false;
}
@Override
public QueryBuilder<M> getQueryBuilder() {
openWritableDb();
return getAbstractDao().queryBuilder();
}
@Override
public List<M> queryRaw(String where, String... selectionArg) {
openWritableDb();
return getAbstractDao().queryRaw(where,selectionArg);
}
}
public class PersonDatabaseManager extends
DatabaseManager<Person,Long> {
public PersonDatabaseManager(Context context) {
super(context);
}
public PersonDatabaseManager(Context context, String dbName) {
super(context, dbName);
}
@Override
public AbstractDao<Person, Long> getAbstractDao() {
return getDaoSession().getPersonDao();
}
}
public class StudentDatabaseManager extends DatabaseManager<Student,String> {
public StudentDatabaseManager(Context context) {
super(context);
}
public StudentDatabaseManager(Context context, String dbName) {
super(context, dbName);
}
@Override
public AbstractDao<Student, String> getAbstractDao() {
return getDaoSession().getStudentDao();
}
}
好,写到这里我们就该结束了吗?no,我们还可以继续,come on baby。
以上的PersonDatabaseManager、StudentDatabaseManager是否可以利用工厂模式来创建了?
答案当然是yes!
普通工厂模式:建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
这样的话就得出了我们下面的类:
public class DatabaseManagerFactory {
public static DatabaseManager getDataManager(Context context, int type) {
switch (type) {
case 0:
return new PersonDatabaseManager(context);
case 1:
return new StudentDatabaseManager(context);
}
return null;
}
}
到此,本次数据库的封装就结束。