Standup Timer的简单工厂Factory和单件模式

前言

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

DAO的包的结构

   Standup Timer的简单工厂Factory和单件模式
  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);
throw new CannotUpdateMeetingException(msg);
}
}

 

TeamDAO.java与MeetingDAO的基本一样。
 

DAOFactroy

  我们先来看看在Model对DAO的调用代码:
代码
private static 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;
}

 

在Model 中 DAOFactory 的实例是由DaoFactory.getMeetingDAO(Context) 方法返回的,而对应的数据库访问类则由 daoFcatroy.getXXXXDAO(Context)方法返回。如果你看过一些有关设计模式的文章就很容易发现,这是单件模式。
  下面来分析一下DAOFactory的代码:
代码
public class DAOFactory {
private static DAOFactory instance = null ;
public static DAOFactory getInstance() {
if (instance == null ) {
instance
= new DAOFactory();
}
return instance;
}

private DAOFactory() {
}
}

 

private DAOFactroy(){} 构造函数私有表明 DAOFactory 无法通过new关键字来实例化。要实例化只能通过静态的方法 getInstance()。在getInstance()方法中首先判断句柄instance是否为null,为空表示DAOFactory的实例尚未创建,然后调用 new DAOFactory() 创建实例(注意!因为是在 DAOFactory内部,所以可以访问private DAOFactory()成员),如果不为null则直接返回已创建的DAOFactory实例。这便是简单的单件模式设计方法(这里并没有考虑到多线程并发的问题,实际上就android的Standup Timer项目本身而言也不存在多线程的并发问题)。单件模式是一种比较简单的设计模式,比较容易理解,大家可以网上搜索一下,有很多相关的文章。
  我们再来看看 MeetDAO  和 TeamDAO的相关代码;
代码
private boolean cacheDAOInstances = false ;
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 {
return new TeamDAO(getProperDAOContext(context));
}
}

public MeetingDAO getMeetingDAO(Context context) {
if (cacheDAOInstances) {
if (cachedMeetingDAO == null ) {
cachedMeetingDAO
= new MeetingDAO(getProperDAOContext(context));
}
return cachedMeetingDAO;
}
else {
return new MeetingDAO(getProperDAOContext(context));
}
}
 private Context getProperDAOContext(Context context) {  
     if (globalContext != null) {            
      return globalContext;       
   } else {          
      return context;     
         } 
   }

 

cacheDAOInstances是布尔值,相当于一个开关,用以判定是否需要对DAO类使用缓存(单件模式)。如果为True则进入单件模式的构建,如果为False 着直接返回一个新的DAO实例。这里通过getMeetingDAO 和getTeamDAO两个方法返回对应的DAO实例。另外getProperDAOContext()方法是负责解决DAOFactory 内的私有变量private Context globalContext  和方法的参数 context 间需要调用哪一个上下文context的冲突。其实我们也可以改写DAOFactory的生成方式:
代码
private static DAOFactory instance = null ;

private Context globalContext = null ;

public static DAOFactory getInstance(Context context) {
if (instance == null ) {
instance
= new DAOFactory(context);


}
return instance;
}

private DAOFactory() {
globalContext
= context;
}

 

这样在其他的方法中就可以省去 context参数。

你可能感兴趣的:(factory)