前言
学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边进行量的积累,一边探索android的学习研究方向。这里我首先选择了jwood的 Standup Timer 项目。
在Standup Timer的 数据访问层net.johnpwood.android.standuptimer.dao使用到了单件模式,我们首先来看一下net.johnpwood.android.standuptimer.dao的项目结构,理解各个类的职责,然后再详细了解其中的设计。
DAO的包的结构

DAO在Standup Timer中充当数据访问层的职责,数据库采用的是SQLite。我们来逐个了解一下上图中各类的职责,他们是负责干什么的!
CannoUpdateMeetingException.java
它继承自RuntimeException类,负责抛出对应的异常。注:private static final long serialVersionUID = 1L;用来表明类序列化时的不同版本间的兼容性,1L为默认值。DuplicateTeamException.java和InvalidTeamNameException.java相同。
DAOFactory.java
这是有所改变的工厂类(与原本的简单工厂模式不太一样,最大的区别在于多态的使用上),负责生产MeetingDAO 、TeamDAO类。
DAOHelper.java
继承自SQLiteOpenHelper,并且实现了DatabaseConstants接口,负责在第一调用时生成对应表和表字段,以及更新数据库。
DatebaseConstants.java
一个包含数据库名称和版本常量的接口,由DAOHelper实现。将数据库名称和版本分离处理,方便日后的版本升级甚至数据库名变更。将数据库名和版本的管理从DAOHelper中分离处理,降低了耦合度,使DAOHelper职责更单一,符合单一职责原则(其实我很难说明将这两个常量放置于接口当中是否妥当)。
MeetingDAO.java
继承自DAOHelper.java负责会议表的具体数据访问业务。因为DAOHelper.java实现了DatebaseConstants接口,所有在MeetingDAO的构造函数当中可以直接调用DATABASE_NAME和DATABASE_VERSION。如果getWritableDatabase()是第一次调用,系统将自动创建数据库和数据库表字段。

public MeetingDAO(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
public Meeting save(Meeting meeting) {
if (meeting.getId() ==null) {
SQLiteDatabase db = getWritableDatabase();
return createNewMeeting(db, meeting);
} else {
String msg ="Attempting to update an existing meeting. Meeting entries cannot be updated.";
Logger.w(msg);
thrownew CannotUpdateMeetingException(msg);
}
}
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
public Meeting save(Meeting meeting) {
if (meeting.getId() ==null) {
SQLiteDatabase db = getWritableDatabase();
return createNewMeeting(db, meeting);
} else {
String msg ="Attempting to update an existing meeting. Meeting entries cannot be updated.";
Logger.w(msg);
thrownew CannotUpdateMeetingException(msg);
}
}
DAOFactroy
我们先来看看在Model对DAO的调用代码:

privatestatic DAOFactory daoFactory = DAOFactory.getInstance();
public Meeting save(Context context) {
MeetingDAO dao =null;
Meeting meeting =null;
try {
dao = daoFactory.getMeetingDAO(context);
meeting = dao.save(this);
} catch (Exception e) {
Logger.e(e.getMessage());
} finally {
dao.close();
}
return meeting;
}
public Meeting save(Context context) {
MeetingDAO dao =null;
Meeting meeting =null;
try {
dao = daoFactory.getMeetingDAO(context);
meeting = dao.save(this);
} catch (Exception e) {
Logger.e(e.getMessage());
} finally {
dao.close();
}
return meeting;
}
下面来分析一下DAOFactory的代码:

publicclass DAOFactory {
privatestatic DAOFactory instance =null;
publicstatic DAOFactory getInstance() {
if (instance ==null) {
instance =new DAOFactory();
}
return instance;
}
private DAOFactory() {
}
}
privatestatic DAOFactory instance =null;
publicstatic DAOFactory getInstance() {
if (instance ==null) {
instance =new DAOFactory();
}
return instance;
}
private DAOFactory() {
}
}
我们再来看看 MeetDAO 和 TeamDAO的相关代码;

privateboolean cacheDAOInstances =false;
private TeamDAO cachedTeamDAO =null;
private MeetingDAO cachedMeetingDAO =null;
private TeamDAO cachedTeamDAO =null;
private MeetingDAO cachedMeetingDAO =null;
public TeamDAO getTeamDAO(Context context) {
if (cacheDAOInstances) {
if (cachedTeamDAO ==null) {
cachedTeamDAO =new TeamDAO(getProperDAOContext(context));
}
return cachedTeamDAO;
} else {
returnnew TeamDAO(getProperDAOContext(context));
}
}
public MeetingDAO getMeetingDAO(Context context) {
if (cacheDAOInstances) {
if (cachedMeetingDAO ==null) {
cachedMeetingDAO =new MeetingDAO(getProperDAOContext(context));
}
return cachedMeetingDAO;
} else {
returnnew MeetingDAO(getProperDAOContext(context));
}
}
private Context getProperDAOContext(Context context) {
if (globalContext != null) {
return globalContext;
} else {
return context;
}
}

privatestatic DAOFactory instance =null;
private Context globalContext =null;
publicstatic DAOFactory getInstance(Context context) {
if (instance ==null) {
instance =new DAOFactory(context);
}
return instance;
}
private DAOFactory() {
globalContext=context;
}
private Context globalContext =null;
publicstatic DAOFactory getInstance(Context context) {
if (instance ==null) {
instance =new DAOFactory(context);
}
return instance;
}
private DAOFactory() {
globalContext=context;
}