當你對一門技術的入門知識都掌握的差不多了,常用的一些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;
}
}
到此,本次數據庫的封裝就結束。