Java私塾:研磨设计模式 之 解释器模式(Interpreter)1

21.1  场景问题

21.1.1  读取配置文件

      考虑这样一个实际的应用,维护系统自定义的配置文件。

几乎每个实际的应用系统都有与应用自身相关的配置文件,这个配置文件是由开发人员根据需要自定义的,系统运行时会根据配置的数据进行相应的功能处理。

      系统现有的配置数据很简单,主要是JDBC所需要的数据,还有默认读取Spring的配置文件,目前系统只需要一个Spring的配置文件。示例如下:

<?xml version="1.0" encoding="UTF-8"?>

<root>

   <jdbc>

      <driver-class>驱动类名</driver-class>

      <url>连接数据库的URL</url>

      <user>连接数据库的用户名</user>

      <password>连接数据库的密码</password>

   </jdbc>

   <application-xml>缺省读取的Spring配置的文件名称</application-xml>

</root>

      现在的功能需求是:如何能够灵活的读取配置文件的内容?

21.1.2  不用模式的解决方案

      不就是读取配置文件吗?实现很简单,直接读取并解析xml就可以了。读取xml的应用包很多,这里都不用,直接采用最基础的Dom解析就可以了。另外,读取到xml中的值过后,后续如何处理,这里也不去管,这里只是实现把配置文件读取并解析出来。

      按照这个思路,很快就写出了实现的代码,示例代码如下:

/**

* 读取配置文件

*/

public class ReadAppXml {

   /**

    * 读取配置文件内容

    * @param filePathName 配置文件的路径和文件名

    * @throws Exception

    */

   public void read(String filePathName)throws Exception{

      Document doc = null;

      //建立一个解析器工厂

      DocumentBuilderFactory factory =

DocumentBuilderFactory.newInstance();

       //获得一个DocumentBuilder对象,这个对象代表了具体的DOM解析器

      DocumentBuilder builder=factory.newDocumentBuilder();

      //得到一个表示XML文档的Document对象

      doc=builder.parse(filePathName);

      //去掉XML中作为格式化内容的空白而映射在DOM树中的Text Node对象

      doc.normalize();


      //获取jdbc的配置值

      NodeList jdbc = doc.getElementsByTagName("jdbc");

      //只有一个jdbc,获取jdbc中的驱动类的名称

      NodeList driverClassNode = ((Element)jdbc.item(0))

.getElementsByTagName("driver-class");

      String driverClass = driverClassNode.item(0)

.getFirstChild().getNodeValue();

      System.out.println("driverClass=="+driverClass);

      //同理获取url、user、password等的值

      NodeList urlNode = ((Element)jdbc.item(0))

.getElementsByTagName("url");

      String url=urlNode.item(0).getFirstChild().getNodeValue();

      System.out.println("url=="+url);


      NodeList userNode = ((Element)jdbc.item(0))

.getElementsByTagName("user");

      String user = userNode.item(0).getFirstChild()

.getNodeValue();

      System.out.println("user=="+user);


      NodeList passwordNode = ((Element)jdbc.item(0))

.getElementsByTagName("password");

      String password = passwordNode.item(0).getFirstChild()

.getNodeValue();

      System.out.println("password=="+password);


      //获取application-xml

      NodeList applicationXmlNode =

doc.getElementsByTagName("application-xml");

      String applicationXml = applicationXmlNode.item(0)

.getFirstChild().getNodeValue();

      System.out.println("applicationXml=="+applicationXml);

   }

}

21.1.3  有何问题

      看了上面的实现,多简单啊,就是最基本的Dom解析嘛,要是采用其它的开源工具包,比如dom4j、jDom之类的来处理,会更简单,这好像不值得一提呀,真的是这样吗?

请思考一个问题:如果配置文件的结构需要变动呢?仔细想想,就会感觉出问题来了。还是先看例子,然后再来总结这个问题。

随着开发的深入进行,越来越多可配置的数据被抽取出来,需要添加到配置文件中,比如与数据库的连接配置:就加入了是否需要、是否使用DataSource等配置。除了这些还加入了一些其它需要配置的数据,例如:系统管理员、日志记录方式、缓存线程的间隔时长、默认读取哪些Spring配置文件等等,示例如下:

<?xml version="1.0" encoding="UTF-8"?>

<root>

   <database-connection>

      <connection-type>连接数据库的类型,1-用Spring集成的方式

(也就是不用下面两种方式了),2-DataSource(就是使用JNDI),

3-使用JDBC自己来连接数据库

      </connection-type>

      <jndi>DataSource的方式用,服务器数据源的JNDI名称</jndi>

      <jdbc>跟上面一样,省略了</jdbc>

   </database-connection>

   <system-operator>系统管理员ID</system-operator>

   <log>

      <operate-type>记录日志的方式,1-数据库,2-文件</operate-type>

      <file-name>记录日志的文件名称</file-name>

   </log>

   <thread-interval>缓存线程的间隔时长</thread-interval>

   <spring-default>

      <application-xmls>

          <application-xml>

缺省读取的Spring配置的文件名称

          </application-xml>

          <application-xml>

其它需要读取的Spring配置的文件名称

          </application-xml>

      </application-xmls>

   </spring-default>

</root>

有朋友可能会想,改变一下配置文件,值得大惊小怪吗?对于应用系统开发来讲,这不是经常发生的、很普通的一件事情嘛。

      的确是这样,改变一下配置文件不是件大事情,但是带来的一系列麻烦也不容忽视,比如:修改了配置文件的结构,那么读取配置文件的程序就需要做出相应的变更;用来封装配置文件数据的数据对象也需要相应的修改;外部使用配置文件的地方,获取数据的地方也会相应变动。

      当然在这一系列麻烦中,最让人痛苦的莫过于修改读取配置文件的程序了,有时候几乎是重写。比如在使用Dom读取第一个配置文件,读取默认的Spring配置文件的值的时候,可能的片断代码示例如下:

//获取application-xml

   NodeList applicationXmlNode =

doc.getElementsByTagName("application-xml");

   String applicationXml = applicationXmlNode.item(0)

.getFirstChild().getNodeValue();

   System.out.println("applicationXml=="+applicationXml);

但是如果配置文件改成第二个,文件的结构发生了改变,需要读取的配置文件变成了多个了,读取的程序也发生了改变,而且application-xml节点也不是直接从doc下获取了。几乎是完全重写了,此时可能的片断代码示例如下:

   //先要获取spring-default,然后获取application-xmls

   //然后才能获取application-xml    

   NodeList springDefaultNode =

doc.getElementsByTagName("spring-default");

   NodeList appXmlsNode = ((Element)springDefaultNode.item(0))

.getElementsByTagName("application-xmls");

   NodeList appXmlNode = ((Element)appXmlsNode.item(0))

.getElementsByTagName("application-xml");

   //循环获取每个application-xml元素的值

   for(int i=0;i<appXmlNode.getLength();i++){

      String applicationXml = appXmlNode.item(i)

.getFirstChild().getNodeValue();

      System.out.println("applicationXml=="+applicationXml);

   }

      仔细对比上面在xml变化前后读取值的代码,你会发现,由于xml结构的变化,导致读取xml文件内容的代码,基本上完全重写了。

问题还不仅仅限于读取元素的值,同样体现在读取属性上。可能有些朋友说可以换不同的xml解析方式来简化,不是还有Sax解析,实在不行换用其它开源的解决方案。

      确实通过使用不同的解析xml的方式是会让程序变得简单点,但是每次xml的结构发生变化过后,或多或少都是需要修改程序中解析xml部分的。

      有没有办法解决这个问题呢?也就是当xml的结构发生改变过后,能够很方便的获取相应元素、或者是属性的值,而不用再去修改解析xml的程序。

更多内容搜索“Java私塾”即可

你可能感兴趣的:(java,配置文件,用户名,连接数据库,解释器)