DAO工厂类的实现

 

在刚开始的时候设计DAO模式的结构时,我们按 一个典型的 DAO 实现有以下组件:

一个 DAO 工厂类
一个 DAO 接口

一个实现了 DAO 接口的具体类

数据传输对象(有时称为值对象
)
  
如何才能使系统通过一种更加灵活地方式来使用不同的实现了 DAO 接口的具体类呢?以下将仿照Springbean工厂,实现一个简单的IOC容器,这种做法的目的,其实就是帮助我们更好地理解DIP,更好地掌握面向 对象编程地一个原则:按接口编程,从而也对Springbean工厂原理有更好地理解。

   通过工厂模式,我们可以依据配置文件或者其它途径得到这些DAO对象的实例,从而使业务处理程序可以方便地调用DAO接口所定义的方法。通过修改DAO 厂的代码,或者修改DAO工厂所使用的配置文件就可以产生DAO对象的不同实例,我们在这里选择后者,因为通过硬编码实现的方式对于相对简单的应用来说可 以接受,但是应用一旦庞大了就不好管理了,通过配置文件来达到具体DAO实现方法的可配置性,大大地增加了系统的灵活性。

   为了方便地进行配置文件的读取,书中采用了Apache软件组织的一个专门用于将XML格式转换为Java对象的公共组件-Commons Digester,有关这个组件地详细介绍我们可以从书中或者网上都可以找到相关的资料。现在我们是抛开Spring等框架地前提下用一些专门地API 实现在工厂类里读取配置文件对各种元素进行解析,获得Java bean,由于这个系统比较小,所以这两个过程在同一个Java对象中完成了。下面我们一步步地来完成这个简单地IOC容器(说它简单是因为只能通过配置 文件中的名字然后把它交给工厂的一个Get方法来访问一个bean组件,没有实现复杂地组装一个对象等功能)

第一步,配置文件的规划和定义(这一步有助于了解什么是控制反转):

   在这里是按照Springbean工厂的配置文件的格式来的,它是一个具有良了结构和可扩展性的配置文件。在这个系统中使用XML格式的文件做配置文件,Digester组件进行解析的方式有很好的扩展性,可以随时增加任意配置项。

   在当前的实例中,所使用的配置项只有DAO的配置,也就是配置每个DAO接口的具体实现对象是哪一个。所以,在这里所规划的配置文件就使用config 素作为配置文件的根元素(其实我们也可以仿照springbeans作为根元素),在config元素内包含了若干个bean元素,其中每个bean 素代表一个DAO接口的实现信息。

经过这样的规划,将这个配置文件命名为MessgeConfig.xnl,具体的实现方法如清单11

清单11

<?xml version="1.0"?>
<config>
<bean id="userDao" type="cn.hxex.message.dao.hibernate.UserDAO" />
<bean id="messageDao" type="cn.hxex.message.dao.hibernate.MessageDAO" />
</config>

    这里的bean元素只有idType两个属性,其中的Type关键字跟Springclass有异曲同工之处,即表示DAO接口的具体实现对象是哪 个,其实这里就很好地体现了像Spring应用框架的控制反转(IOC)容器,特点很好地在这里表现出来了,真正地达到了针对接口编程,不是抽象依赖于实 现而是反过来实现依赖于抽象,即我们如果想要在业务层实现什么样的功能就直接在接口里定义一个方法(留个参数,用来跟实体对象关联),然后我们就不用管底 层是怎么技术来处理持久化细节了,使组件达到了可复用地目的。在这里,如果将来不使用Hibernate作为持久层组件了,或者通过其他方法实现了持久层 的操作,那么只需要在这里进行相应的配置就可以使这个系统轻松地改变持久层的实现方法,而业务处理层和显示层则不需要进行任何改动了。我想这些动机就是所 有的Ioc容器的出发点吧。

      第二步,定义配置对象(做完这一步可以更好地了解Springbean工厂的内部工作情况)

   完成了配置文件的定义后还需要定义一系列的对象来表示这个配置文件,这里使用的定义原则是每个用于表示配置文件的对象与一个配置文件中的元素相对应,但这 也不是绝对的,对于非常简单的元素则不需要定义单独的对象来表示。由于这个系统的配置文件比较简单,所以用于表示配置文件的对象就比较简单。在这里,用 MessageConfig对象与配置文件中的config元素相对应,而BeanConfig则与bean元素相对应。下面的两个清单是这两个对象的具 体实现方法,具体地实现过程与细节我们就不必深究了,也不是我们关心地重点,因为我们以后可以用Spring等其它的框架来直接用它们的配置文件就可以了 ~~~

   清单12

    /**
*
系统配置信息类

*/
public class MessageConfig
{
public static Hashtable beans;

/**
*
构造函数

*/
public MessageConfig()
{
   beans = new Hashtable();
}

/**
*
增加一个BeanConfig对象

* @param bean
*/
public void addBean(BeanConfig bean)
{
   beans.put(bean.getId(), bean);
}

/**
*
得到一个DAO接口对象的实例

* @param name DAO
接口对象的名称
* @return
指定DAO接口的实现类的实例
*/
public Object getBean(String name)
{
   BeanConfig config = (BeanConfig) beans.get(name);

   if (config == null)
   {
    throw new MessageException("Couldn't find the bean: " + name);
   }

   return config.getInstance();
}

public String toString()
{
   return ReflectionToStringBuilder.toString(this);
}
}

清单13

public class BeanConfig
{
private String id;
private String type;

public String getId() {
   return id;
}
public void setId(String id) {
   this.id = id;
}

public String getType() {
   return type;
}
public void setType(String type) {
   this.type = type;
}

private Object instance;
public Object getInstance()
{
   if( null!=instance ) return instance;
  
   try
   {
    Class cls = Class.forName( getType() );
    instance = cls.newInstance();
    return instance;
   }
   catch( Exception ex )
   {
    throw new MessageException( "Couldn't find class:" + getType() );
   }
}

public String toString()
{
   return ReflectionToStringBuilder.toString( this );
}
}
最后一步,生成bean工厂类(做完这一步就知道Springbean工厂功能是如此强大)

这里主要完成的任务是进行配置文件的处理,并实现相应的bean工厂类的编写,前面已经提到过了,由于这个系统比较小,所以读取配置文件,生成配置对象的 实例都在工厂类里完成了。最好地做法就是抽取出那些读取配置文件,还有生成对象实例都放在另外一个独立的类里。而bean工厂实现一个生成bean的方 法,可以根据beanid值得到相应bean实例。同样地,在这里如何解析XML配置文件并转化成Java对象的实例的功能是也不是我们关注的重点,了 解下Digester就行了:

清单13

public class DaoFactory
{
    private static Log log = LogFactory.getLog(DaoFactory.class);

public static final MessageConfig messageConfig;

static
{
   Digester digester = new Digester();
   digester.setValidating( false );
  
   digester.addObjectCreate( "config", "cn.hxex.message.config.MessageConfig" );
   digester.addSetProperties( "config" );
  
   digester.addObjectCreate( "config/bean", "cn.hxex.message.config.BeanConfig" );
   digester.addSetProperties( "config/bean" );
   digester.addSetNext( "config/bean", "addBean", "cn.hxex.message.config.BeanConfig" );
  
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   InputStream in = classLoader.getResourceAsStream( "MessageConfig.xml" );
   MessageConfig config = null;
   try {
    if( in!=null )
     config = (MessageConfig)digester.parse( in );
   } catch (IOException e) {
    e.printStackTrace();
   } catch (SAXException e) {
    e.printStackTrace();
   }
   messageConfig = config;
}

public static Object getDao( String name )
{
   if( null==messageConfig ) return null;
  
   return messageConfig.getBean( name );
}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值