﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-wjywilliam-文章分类-Java</title><link>http://www.blogjava.net/wjywilliam/category/17458.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 07 Mar 2008 13:20:21 GMT</lastBuildDate><pubDate>Fri, 07 Mar 2008 13:20:21 GMT</pubDate><ttl>60</ttl><item><title>一个体现Java接口及工厂模式优点的例子 &amp; 设计模式之Factory</title><link>http://www.blogjava.net/wjywilliam/articles/184575.html</link><dc:creator>wjywilliam</dc:creator><author>wjywilliam</author><pubDate>Fri, 07 Mar 2008 10:11:00 GMT</pubDate><guid>http://www.blogjava.net/wjywilliam/articles/184575.html</guid><wfw:comment>http://www.blogjava.net/wjywilliam/comments/184575.html</wfw:comment><comments>http://www.blogjava.net/wjywilliam/articles/184575.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wjywilliam/comments/commentRss/184575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wjywilliam/services/trackbacks/184575.html</trackback:ping><description><![CDATA[<p>我们先来看看这两篇文章：<br />
</p>
<p><span style="font-size: 18pt">设计模式之Factory<br />
</span></p>
<p><br />
<a href="http://www.jdon.com/aboutme.htm"><u><font color="#0000ff">板桥里人</font></u></a> http://www.jdon.com 2002/10/07（转载请保留）</p>
<p><strong><em>工厂模式定义<span lang="EN-US" xml:lang="EN-US">:提供创建对象的接口.</span></em></strong></p>
<p><strong><em>为何使用<span lang="EN-US" xml:lang="EN-US">?</span></em></strong><span lang="EN-US" xml:lang="EN-US"><br />
工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式，工厂模式在Java程序系统可以说是随处可见。</span></p>
<p>为什么工厂模式是如此常用？因为工厂模式就相当于创建实例对象的<span lang="EN-US" xml:lang="EN-US">new，我们经常要根据类Class生成实例对象，如A a=new A() 工厂模式也是用来创建实例对象的，所以以后new时就要多个心眼，是否可以考虑实用工厂模式，虽然这样做，可能多做一些工作，但会给你系统带来更大的可扩展性和尽量少的修改量。</span></p>
<p>我们以类<span lang="EN-US" xml:lang="EN-US">Sample为例， 如果我们要创建Sample的实例对象:</span></p>
<p><span lang="EN-US" xml:lang="EN-US">Sample sample=new Sample();</span></p>
<p>可是，实际情况是，通常我们都要在创建<span lang="EN-US" xml:lang="EN-US">sample实例时做点初始化的工作,比如赋值 查询数据库等。</span></p>
<p>首先，我们想到的是，可以使用<span lang="EN-US" xml:lang="EN-US">Sample的构造函数，这样生成实例就写成:</span></p>
<p><span lang="EN-US" xml:lang="EN-US">Sample sample=new Sample(参数);</span></p>
<p>但是，如果创建<span lang="EN-US" xml:lang="EN-US">sample实例时所做的初始化工作不是象赋值这样简单的事，可能是很长一段代码，如果也写入构造函数中，那你的代码很难看了（就需要Refactor重整）。</span></p>
<p>为什么说代码很难看，初学者可能没有这种感觉，我们分析如下，初始化工作如果是很长一段代码，说明要做的工作很多，将很多工作装入一个方法中，相当于将很多鸡蛋放在一个篮子里，是很危险的，这也是有背于<span lang="EN-US" xml:lang="EN-US">Java面向对象的原则，面向对象的封装(Encapsulation)和分派(Delegation)告诉我们，尽量将长的代码分派&#8220;切割&#8221;成每段，将每段再&#8220;封装&#8221;起来(减少段和段之间偶合联系性)，这样，就会将风险分散，以后如果需要修改，只要更改每段，不会再发生牵一动百的事情。</span></p>
<p>在本例中，首先，我们需要将创建实例的工作与使用实例的工作分开<span lang="EN-US" xml:lang="EN-US">, 也就是说，让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。</span></p>
<p>这时我们就需要<span lang="EN-US" xml:lang="EN-US">Factory工厂模式来生成对象了，不能再用上面简单new Sample(参数)。</span>还有<span lang="EN-US" xml:lang="EN-US">,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.</span>现在<span lang="EN-US" xml:lang="EN-US">Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:</span></p>
<p><span lang="EN-US" xml:lang="EN-US">Sample mysample=new MySample();<br />
Sample hissample=new HisSample();</span></p>
<p>随着项目的深入<span lang="EN-US" xml:lang="EN-US">,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.</span></p>
<p>但如果你一开始就有意识使用了工厂模式<span lang="EN-US" xml:lang="EN-US">,这些麻烦就没有了.</span></p>
<p><strong>工厂方法<br />
</strong>你会建立一个专门生产<span lang="EN-US" xml:lang="EN-US">Sample实例的工厂:</span></p>
<p>
<table style="width: 80%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="80%" border="0">
    <tbody>
        <tr>
            <td style="padding-right: 2.25pt; padding-left: 2.25pt; background: #cccccc; padding-bottom: 2.25pt; padding-top: 2.25pt">
            <p><span lang="EN-US" xml:lang="EN-US">public class Factory{</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public static Sample creator(int which){</span></p>
            <p>　　//getClass <span lang="EN-US" xml:lang="EN-US">产生Sample 一般可使用动态类装载装入类。<br />
            　　if (which==1)<br />
            　　　　return new SampleA();<br />
            　　else if (which==2)<br />
            　　　　return new SampleB();</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>那么在你的程序中<span lang="EN-US" xml:lang="EN-US">,如果要实例化Sample时.就使用</span></p>
<p><span lang="EN-US" xml:lang="EN-US">Sample sampleA=Factory.creator(1);</span></p>
<p>这样<span lang="EN-US" xml:lang="EN-US">,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵.</span></p>
<p>使用工厂方法 要注意几个角色，首先你要定义产品接口，如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类，用来生成产品Sample，如下图，最右边是生产的对象Sample：</p>
<p>&nbsp;<img alt="" src="http://www.blogjava.net/images/blogjava_net/wjywilliam/29942/o_factory.jpg" border="0" /></p>
<p>进一步稍微复杂一点，就是在工厂类上进行拓展，工厂类也有继承它的实现类concreteFactory了<strong><em>。</em></strong></p>
<p><span lang="EN-US" xml:lang="EN-US"><strong>抽象工厂</strong><br />
工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).</span></p>
<p style="margin-bottom: 12pt"><span lang="EN-US" xml:lang="EN-US">这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.</span></p>
<p style="margin-bottom: 12pt">这里假设：Sample有两个concrete类SampleA和SamleB，而Sample2也有两个concrete类Sample2A和SampleB2</p>
<p style="margin-bottom: 12pt"><span lang="EN-US" xml:lang="EN-US">那么，我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现，下面就是将上例中的Factory拓展成抽象工厂:</span></p>
<p>
<table style="width: 80%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td style="padding-right: 2.25pt; padding-left: 2.25pt; background: #cccccc; padding-bottom: 2.25pt; padding-top: 2.25pt">
            <p><span lang="EN-US" xml:lang="EN-US">public abstract class Factory{</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public abstract Sample creator();</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public abstract Sample2 creator(String name); </span></p>
            <p><span lang="EN-US" xml:lang="EN-US">}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">public class SimpleFactory extends Factory{</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public Sample creator(){<br />
            　　　　.........<br />
            　　　　return new SampleA</span><span lang="EN-US" xml:lang="EN-US"><br />
            　　}</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public Sample2 creator(String name){<br />
            　　　　.........<br />
            　　　　return new Sample2A</span><span lang="EN-US" xml:lang="EN-US"><br />
            　　}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">public class BombFactory extends Factory{</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public Sample creator(){<br />
            　　　　......<br />
            　　　　return new SampleB</span><span lang="EN-US" xml:lang="EN-US"> <br />
            　　}</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public Sample2 creator(String name){<br />
            　　　　......<br />
            　　　　return new Sample2B<br />
            　　}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">&nbsp;</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span lang="EN-US" xml:lang="EN-US">从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问，为什么我不可以使用两个工厂方法来分别生产Sample和Sample2? </span></p>
<p><span lang="EN-US" xml:lang="EN-US">抽象工厂还有另外一个关键要点，是因为 SimpleFactory内，生产Sample和生产Sample2的方法之间有一定联系，所以才要将这两个方法捆绑在一个类中，这个工厂类有其本身特征，也许制造过程是统一的，比如：制造工艺比较简单，所以名称叫SimpleFactory。</span><span lang="EN-US" xml:lang="EN-US"><br />
</span></p>
<p>在实际应用中，工厂方法用得比较多一些，而且是和动态类装入器组合在一起应用，</p>
<p><span lang="EN-US" xml:lang="EN-US"><strong>举例</strong> <O:P></O:P></span></p>
<p>我们以<span lang="EN-US" xml:lang="EN-US">Jive的ForumFactory为例，这个例子在前面的Singleton模式中我们讨论过，现在再讨论其工厂模式:</span></p>
<p>
<table style="width: 97%; mso-cellspacing: 2.2pt; mso-padding-alt: 2.25pt 2.25pt 2.25pt 2.25pt" cellspacing="3" cellpadding="0" width="97%" border="0">
    <tbody>
        <tr>
            <td style="padding-right: 2.25pt; padding-left: 2.25pt; background: #cccccc; padding-bottom: 2.25pt; padding-top: 2.25pt">
            <p><span lang="EN-US" xml:lang="EN-US">public abstract class ForumFactory {</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">private static Object initLock = new Object();<br />
            　　private static String className = "com.jivesoftware.forum.database.DbForumFactory";<br />
            　　private static ForumFactory factory = null; </span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">public static ForumFactory getInstance(Authorization authorization) {<br />
            　　　　//If no valid authorization passed in, return null.<br />
            　　　　if (authorization == null) {<br />
            　　　　　　return null;<br />
            　　　　}<br />
            　　　　//以下使用了Singleton 单态模式<br />
            　　　　if (factory == null) {<br />
            　　　　　　synchronized(initLock) {<br />
            　　　　　　　　if (factory == null) {<br />
            　　　　　　　　　　　　...... </span></p>
            <p>　　　　　　　　　　<span lang="EN-US" xml:lang="EN-US">try {<br />
            　　　　　　　　　　　　　　//动态转载类<br />
            　　　　　　　　　　　　　　Class c = Class.forName(className);<br />
            　　　　　　　　　　　　　　factory = (ForumFactory)c.newInstance();<br />
            　　　　　　　　　　}<br />
            　　　　　　　　　　catch (Exception e) {<br />
            　　　　　　　　　　　　　　return null;<br />
            　　　　　　　　　　}<br />
            　　　　　　　　}<br />
            　　　　　　}<br />
            　　　　}</span></p>
            <p>　　　　<span lang="EN-US" xml:lang="EN-US">//Now, 返回 proxy.用来限制授权对forum的访问<br />
            　　　　return new ForumFactoryProxy(authorization, factory,<br />
            　　　　　　　　　　　　　　　　　　　　factory.getPermissions(authorization));<br />
            　　}</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">//真正创建forum的方法由继承forumfactory的子类去完成.<br />
            　　public abstract Forum createForum(String name, String description)<br />
            　　throws UnauthorizedException, ForumAlreadyExistsException;</span></p>
            <p>　　<span lang="EN-US" xml:lang="EN-US">....</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">}</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">&nbsp;</span></p>
            <p><span lang="EN-US" xml:lang="EN-US">&nbsp;</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>因为现在的<span lang="EN-US" xml:lang="EN-US">Jive是通过数据库系统存放论坛帖子等内容数据,如果希望更改为通过文件系统实现,这个工厂方法ForumFactory就提供了提供动态接口:</span></p>
<p><span lang="EN-US" xml:lang="EN-US">private static String className = "com.jivesoftware.forum.database.DbForumFactory";</span></p>
<p>你可以使用自己开发的创建<span lang="EN-US" xml:lang="EN-US">forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.</span></p>
<p>在上面的一段代码中一共用了三种模式<span lang="EN-US" xml:lang="EN-US">,除了工厂模式外,还有Singleton单态模式,以及proxy模式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效果. &nbsp;</span></p>
<p>看看<span lang="EN-US" xml:lang="EN-US">Java宠物店中的CatalogDAOFactory:</span></p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#cccccc" border="0">
    <tbody>
        <tr>
            <td>public class CatalogDAOFactory {
            <p>&nbsp;</p>
            <p>　　/**</p>
            <p>　　* 本方法制定一个特别的子类来实现DAO模式。<br />
            　　* 具体子类定义是在J2EE的部署描述器中。<br />
            　　*/</p>
            <p>　　public static CatalogDAO getDAO() throws CatalogDAOSysException {</p>
            <p>　　　　CatalogDAO catDao = null;</p>
            <p>　　　　try {</p>
            <p>　　　　　　InitialContext ic = new InitialContext();<br />
            　　　　　　//动态装入CATALOG_DAO_CLASS<br />
            　　　　　　//可以定义自己的CATALOG_DAO_CLASS，从而在无需变更太多代码<br />
            　　　　　　//的前提下，完成系统的巨大变更。</p>
            <p>　　　　　　String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);</p>
            <p>　　　　　　catDao = (CatalogDAO) Class.forName(className).newInstance();</p>
            <p>　　　　} catch (NamingException ne) {</p>
            <p>　　　　　　throw new CatalogDAOSysException("<br />
            　　　　　　　　CatalogDAOFactory.getDAO: NamingException while <br />
            　　　　　　　　　　getting DAO type : \n" + ne.getMessage());</p>
            <p>　　　　} catch (Exception se) {</p>
            <p>　　　　　　throw new CatalogDAOSysException("<br />
            　　　　　　　　CatalogDAOFactory.getDAO: Exception while getting <br />
            　　　　　　　　　　DAO type : \n" + se.getMessage());</p>
            <p>　　　　}</p>
            <p>　　　　return catDao;</p>
            <p>　　}</p>
            <p>}<br />
            </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><br style="mso-ignore: vglayout" clear="all" />
</p>
<p><span lang="EN-US" xml:lang="EN-US">CatalogDAOFactory是典型的工厂方法，catDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类，这个实现子类在Java宠物店是用来操作catalog数据库，用户可以根据数据库的类型不同，定制自己的具体实现子类，将自己的子类名给与CATALOG_DAO_CLASS变量就可以。</span></p>
<p>由此可见，工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制，只要我们更换一下具体的工厂方法，系统其他地方无需一点变换，就有可能将系统功能进行改头换面的变化。</p>
<p>设计模式如何在具体项目中应用见<a href="http://www.jdon.com/mybook/index.htm" target="_blank"><u><font color="#810081">《Java实用系统开发指南》</font></u></a><br />
<br />
</p>
<p>--------------------------------------------------------------------------------------------------------------------------------------------------------------</p>
<h3><strong>一个体现Java接口及工厂模式优点的例子(转载自<a href="http://www.jspcool.com/j2se/20071019225405.htm">http://www.jspcool.com/j2se/20071019225405.htm</a>)</strong></h3>
<p>随着模式概念的普及，了解模式和使用模式的程序员越来越多，很多人在学习模式的时候，都会有这样一种疑惑：&#8220;有必要搞得这么复杂吗？&#8221;。的确，因为教程的例子过于简单化（这样方便读者学习），或者是作者选例子的时候并没有很好体现所讲模式的优点，很多情况下如果仅就其例子的问题来说，用模式是太复杂了。因此才导致这样的误解：&#8220;模式就是把简单的问题复杂化吗？&#8221;。当然不是，随着你开发实践的不断丰富，你终会发现模式强大威力，而且模式也并非贵族化的编程方式，它就是一些经过提炼了的解决问题的方法技巧。 </p>
<p>通过学习模式，程序员开始告别过去准直线式的代码方式，模式开扩了我们的视野，强化了我们面向对象编程的思维方式。然而现在又出现了另一个普遍的问题，盲目应用模式。模式是问题的解决方案，先有问题才有模式，模式是依附于所要解决的问题的而生的。必须了解模式在很多情况下是以提高代码的复杂度为代价来增强灵活性、可复用性。如果在自已的代码中使用某一模式仅只提高了代码的复杂度，而其它方面收效甚微，或者某部份代码根本就不存在灵活性及高复用性的需求，那么我们就没有必要为使用模式而放弃更直观简单的代码写法。 </p>
<p>一流的高手90%精力关注问题的解决方案，因为找到了好的解决方案，再写起代码会很轻松代码也简洁流畅，看这样的代码是一种享受和提高；二流的熟手90%精力关注代码实现，因为问题的解决方案并非最佳，实现的代码也会比较复杂；三流菜鸟记流水帐,90%精力在敲键盘，常常做了大半才发现行不通，回过头来再用90%的时间敲键盘，根本不会用到任何模式，写出来的代码的只有他自已才能看懂。做出来的软件也是支离破碎，做一丁点改动都要大费周折，而且你还不知道改动后会产生什么问题，大有住危房里的感觉。 </p>
<p>在这里还是举一个滥用模式的例子吧。我曾参与过一个大集团公司ＯＡ系统的第二期开发，开发沿用原有代码架构并增加新的功能模块。文档很少我读原代码时就被它程序里的代码转来转去搞得头大如斗，最后读懂了：原代码架构总体采用工厂模式，而且是最复杂的抽象工厂模式。它把所有模块类都通过工厂生成还工厂套工厂，并且每一个模块类都有一个接口，每个接口也只有一个模块现实类，因为涉及权限控制还用了代理(proxy)模式。　读懂代码后我开始嵌入代码，发现每新增一个类，都要到六个Java文件中去增加相应代码，而在类中每增加一个方法，也要到它的接口等四个Java文件中去增加相应代码。天呀！！！记得当时我的小姆指常会不听使唤，就是因为频繁的使用Ctrl+C 、Ctrl+V，小姆指按着Ctrl键给累的。整个项目组苦不堪言，真烦透了。项目结束后我回顾发现：代理模式用得还对（现在针对权限这类横向控制有AOP编程这种新的解决办法了）但工厂模式在这里根本就是画蛇添足，不仅没有解决什么问题，反而增加代码复杂度和耦合性，降低了开发效率连维护难度都提高了。而且那种每个类简单的加一个接口的方式，更是没有道理，这让我很想说周星驰说过的一句话：&#8220;球~~~不是这么踢~~~~的，接口~~~不是这么用~~~的&#8221;。言归正传，我们先来看这样一个常见问题：某系统需要支持多种类型的数据库。用过Oracle、MSSQL等数据库的人都知道，它们的SQL编写方式都各有些不同。比如说Oracle的唯一标识自动+1字段用的是序列，MSSQL改一下字段属性就成了，还有各种各自特有的SQL用法。为了支持多数据库，难道我们要开发多套系统？当然NO。请看下面的解决方案。 </p>
<p>即然数据库存在多种，我们可以将系统中所有对数据库的操作抽象出来，写成一个个方法组合到一个类中，有几种数据库我们就写几个这样的类。具体设计类图如下： </p>
<p>&nbsp;</p>
<p><br />
简要说明： <br />
OracleDataOperate、SqlserverDataOperate、MysqlDataOperate，分别代表Oracle、Sqlserver、Mysql这三种数据库的操作类。继承自AbstractDataOperate <br />
AbstractDataOperate是一个抽象类，包含了那些不同种类数据库都是一样代码的操作方法。继承自DataOperate <br />
DataOperate是上面说的数据操作类的统一接口，只有两个方法：取得一条记录、插入一条记录。 <br />
DataOperateFactory是一个工厂方法，统一用它的方法来得到数据库操作类的实例。 <br />
SampleClass是我们系统的某个功能模块的类。 <br />
People是一个实体类，代表一条记录。三个字段　oid唯一标识符、name姓名、date生日。 </p>
<p>详细说明： <br />
１、所有系统功能模块类只认DataOperat这个接口还不必管具体的实现类是OracleDataOperate还SqlserverDataOperate。DataOperate源代码如下： <br />
public interface DataOperate { <br />
//根据记录的唯一标识取出一条记录 <br />
People getPeople(String oid); <br />
//插入一条记录 <br />
boolean insertPeople(People people); <br />
} </p>
<p>２、AbstractDataOperate、OracleDataOperate、SqlserverDataOperate、MysqlDataOperate都是继承DataOperate接口的，没什么好说的，省略。 </p>
<p>３、DataOperateFactory。我们看看工厂方法怎么写的。 <br />
public class DataOperateFactory { <br />
public static final int ORACLE = 0; //定义三个表示数据库类型的常量 <br />
public static final int MYSQL = 1; <br />
public static final int SQLSERVER = 2; </p>
<p>private static DataOperate db; <br />
private static int dataType = MYSQL; <br />
/** <br />
* 根据数据库类型(dataType)取得一个数据库操作类的实例， <br />
* 这里对DataOperate使用了单例模式，因为OracelDataOperate等都是无状态的工具类， <br />
* 所以整个系统只保留一个实例就行了。 <br />
* <br />
* @return 返回的是接口，客户端不必关心具体是用那个实现类 <br />
*/ <br />
public static DataOperate getInstance() { <br />
if (db == null) { <br />
if (dataType == ORACLE) //根据dateType返回相应的实现类 <br />
return new OracelDataOperate(); <br />
if (dataType == MYSQL) <br />
return new MysqlDataOperate(); <br />
if (dataType == SQLSERVER) <br />
return new SqlserverDataOperate(); <br />
} <br />
return db; <br />
} <br />
} </p>
<p>４、接下来就看看使用端是如何调用工厂方法和使用数据操作类的。 <br />
/** <br />
* 系统某个功能类 <br />
*/ <br />
public class SampleClass { <br />
private DataOperate db; //声明一个数据库操作类，注意这里用的是接口噢 <br />
/**某方法*/ <br />
public void sampleMethod() { <br />
db = DataOperateFactory.getInstance();//得到单一实例 <br />
People p = db.getPeople("123"); //取得一条记录 <br />
db.insertPeople(p);//再插回去 <br />
} <br />
} </p>
<p>　　我们发现SampleClass中根本没有出现OracelDataOperate、MysqlDataOperate等的影子，这就是接口的威力。客户端不必针对OracelDataOperate等写不同的代码，它只关心DataOperate即可，具体要取那个类的逻辑就由DataOperateFactory负责了。 </p>
<p>总结： <br />
从例子中我们可以看到什么是面向接口的编程方式。SampleClass使用数据操作类可以不必关心具体是那个类，只要是符合接口的都行 <br />
要实例？只须调用DataOperateFactory.getInstance()即可，其它的交于DataOperateFactory这个工厂来做吧，使用端什么都不用关心。 <br />
我们要支持新的数据库类型，只须要象OracelDataOperate那样，再写一个继承AbstractDataOperate的类即可，比如SysbaseDataOperate。然后到DataOperateFactory中加入相应代码即可。 <br />
如果我们想要可配置性更高，可以用private static int dataType = MYSQL;中的值设置到一个文本文件中。 <br />
　　对于开发支持多种数据库的系统，强烈建议使用hibernate，我现在做的系统就是用hibernate的，开发时用Mysql，到要给客户时将数据库换了DB2，程序不用做任何改动，真正的无逢移植。不过这样，本文所提到的方法就没什么用了.<br />
</p>
<p><br />
&nbsp;</p>
<p>这两篇是我找到的关于Factory Mode的文章，但是前面的论述很好，后面的例子却不怎么样，特别是第二篇的例子并不符合实际也没必要这样做，纯粹是接口也可以实现，Factory Mode并没有体现多少。第一篇的就似乎比较切实，但是说的也不够清晰。</p>
<img src ="http://www.blogjava.net/wjywilliam/aggbug/184575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wjywilliam/" target="_blank">wjywilliam</a> 2008-03-07 18:11 <a href="http://www.blogjava.net/wjywilliam/articles/184575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java文件操作大全(Jsp版)</title><link>http://www.blogjava.net/wjywilliam/articles/122059.html</link><dc:creator>wjywilliam</dc:creator><author>wjywilliam</author><pubDate>Tue, 05 Jun 2007 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/wjywilliam/articles/122059.html</guid><wfw:comment>http://www.blogjava.net/wjywilliam/comments/122059.html</wfw:comment><comments>http://www.blogjava.net/wjywilliam/articles/122059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wjywilliam/comments/commentRss/122059.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wjywilliam/services/trackbacks/122059.html</trackback:ping><description><![CDATA[<p>Java文件操作大全 </p>
<p>文件的建立/检查与删除 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;文件的建立、检查与删除&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath(""); <br>//out.println(path); <br>File f=new File(path,"File.txt"); <br>//out.println(f); <br>//out.println(f.exists()); </p>
<p>if(f.exists()){//检查File.txt是否存在 <br>f.delete();//删除File.txt文件 <br>out.println(path + "<a href="file://File.txt/">\\File.txt</a> 存在，已删除。"); <br>}else{ <br>f.createNewFile();//在当前目录下建立一个名为File.txt的文件 <br>out.println(path + "<a href="file://File.txt/">\\File.txt</a> 不存在，已建立。");//输出目前所在的目录路径 <br>} <br>%&gt; </p>
<p>目录的建立/检查与删除<br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;目录的建立/检查与删除&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath(""); <br>path=path + "<a href="file://Sub%22;//">\\Sub";//</a>将要建立的目录路径 <br>File d=new File(path);//建立代表Sub目录的File对象，并得到它的一个引用 <br>if(d.exists()){//检查Sub目录是否存在 <br>d.delete(); <br>out.println("Sub目录存在，已删除"); <br>}else{ <br>d.mkdir();//建立Sub目录 <br>out.println("Sub目录不存在，已建立"); <br>} <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>如何在JSP中处理虚拟目录<br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;JSP中如何处理虚拟目录&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>取得虚拟目录对应的磁盘路径&lt;br&gt; <br>Web站点主目录的位置为&lt;font color=#ff0000&gt;&lt;%=request.getRealPath("/")%&gt;&lt;/font&gt;&lt;br&gt; <br>JSP网页所在的目录位置&lt;font color=#ff0000&gt;&lt;%=request.getRealPath("./")%&gt;&lt;/font&gt;&lt;br&gt; <br>JSP网页所在目录上一层目录的位置&lt;font color=#ff0000&gt;&lt;%=request.getRealPath("../")%&gt;&lt;/font&gt;&lt;br&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>文件属性的取得 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.util.Date,java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;文件属性的取得&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("/"); <br>File f=new File(path,"ReadData.txt"); <br>if(f.exists()){ <br>%&gt; <br>&lt;%=f.getName()%&gt;的属性如下：&lt;br&gt;&lt;br&gt; <br>文件长度为：&lt;%=f.length()%&gt; <br>&lt;%=f.isFile()?"是文件":"不是文件"%&gt;&lt;br&gt; <br>&lt;%=f.isDirectory()?"是目录":"不是目录"%&gt;&lt;br&gt; <br>&lt;%=f.canRead()?"可读取":"不可读取"%&gt;&lt;br&gt; <br>&lt;%=f.canWrite()?"可写入":"不可写入"%&gt;&lt;br&gt; <br>&lt;%=f.isHidden()?"是隐藏文件":"不是隐藏文件"%&gt;&lt;br&gt; <br>文件的最后修改日期为：&lt;%=new Date(f.lastModified())%&gt;&lt;br&gt; <br>&lt;% <br>}else{ <br>f.createNewFile();//在当前目录下建立一个名为ReaData.txt的文件 <br>%&gt; <br>&lt;%=f.getName()%&gt;的属性如下：&lt;br&gt;&lt;br&gt; <br>文件长度为：&lt;%=f.length()%&gt; <br>&lt;%=f.isFile()?"是文件":"不是文件"%&gt;&lt;br&gt; <br>&lt;%=f.isDirectory()?"是目录":"不是目录"%&gt;&lt;br&gt; <br>&lt;%=f.canRead()?"可读取":"不可读取"%&gt;&lt;br&gt; <br>&lt;%=f.canWrite()?"可写入":"不可写入"%&gt;&lt;br&gt; <br>&lt;%=f.isHidden()?"是隐藏文件":"不是隐藏文件"%&gt;&lt;br&gt; <br>文件的最后修改日期为：&lt;%=new Date(f.lastModified())%&gt;&lt;br&gt; <br>&lt;% <br>} <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>取出目录中文件的方法<br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;取出目录中文件的方法--列出目录中的文件&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("/"); <br>File d=new File(path);//建立当前目录中文件的File对象 <br>File list[]=d.listFiles();//取得代表目录中所有文件的File对象数组 <br>out.println("&lt;font color=#ff0000&gt;" + path + "目录下的文件：&lt;/font&gt;&lt;br&gt;"); <br>for(int i=0;i&lt;list.length;i++){ <br>if(list&lt;I&gt;.isFile()){ <br>out.println(list&lt;I&gt;.getName() + "&lt;br&gt;"); <br>} <br>} <br>out.println("&lt;br&gt;&lt;font color=#ff0000&gt;" + path + "目录下的目录：&lt;/font&gt;&lt;br&gt;"); <br>for(int i=0;i&lt;list.length;i++){ <br>if(list&lt;I&gt;.isDirectory()){ <br>out.println(list&lt;I&gt;.getName() + "&lt;br&gt;"); <br>} <br>} <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>判断是否为空白文件<br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;判断是否为空白文件&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("/"); <br>out.println(path); <br>FileReader fr=new FileReader(path + "<a href="file://AtEnd.txt%22);//">\\AtEnd.txt");//</a>建立FileReader对象，并实例化为fr <br>//对FileReader类生成的对象使用read()方法，可以从字符流中读取下一个字符。 <br>if(fr.read()==-1)//判断是否已读到文件的结尾 <br>{ <br>out.print("AtEnd.txt文件中没有数据&lt;br&gt;"); <br>}else{ <br>out.println("AtEnd.txt文件中有数据"); <br>} <br>fr.close(); <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>读取所有的文件数据 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*,java.lang.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;读取所有的文件数据&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("."); <br>FileReader fr=new FileReader(path + "<a href="file://ReadData.txt/">\\ReadData.txt</a>"); <br>//关键在于读取过程中，要判断所读取的字符是否已经到了文件的末尾，并且这个字符是不是文件中的断行符，即判断该字符值是否为13。 <br>int c=fr.read();//从文件中读取一个字符 <br>//判断是否已读到文件结尾 <br>while(c!=-1){ <br>out.print((char)c);//输出读到的数据 <br>c=fr.read();//从文件中继续读取数据 <br>if(c==13){//判断是否为断行字符 <br>out.print("&lt;br&gt;");//输出分行标签 <br>fr.skip(1);//略过一个字符 <br>//c=fr.read();//读取一个字符 <br>} <br>} <br>fr.close(); <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>一行一行读取数据 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;文件读取&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("");//取得当前目录的路径 <br>FileReader fr=new FileReader(path + "<a href="file://file//inc//t.txt%22);//">\\file\\inc\\t.txt");//</a>建立FileReader对象，并实例化为fr <br>BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br <br>String Line=br.readLine();//从文件读取一行字符串 <br>//判断读取到的字符串是否不为空 <br>while(Line!=null){ <br>out.println(Line + "&lt;br&gt;");//输出从文件中读取的数据 <br>Line=br.readLine();//从文件中继续读取一行数据 <br>} <br>br.close();//关闭BufferedReader对象 <br>fr.close();//关闭文件 <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>略过文件中的字符不读取 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;略过字节不读取&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("."); <br>FileReader fr=new FileReader(path + "<a href="file://ReadData.txt/">\\ReadData.txt</a>"); <br>fr.skip(2);//跳过2个字节 <br>int c=fr.read();//读取一个字节 <br>while(c!=-1){ <br>out.print((char)c); <br>c=fr.read(); <br>} <br>fr.close(); <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>将数据写入文件 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;将数据写入文件&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("."); <br>FileWriter fw=new FileWriter(path + "<a href="file://WriteData.txt%22);//">\\WriteData.txt");//</a>建立FileWriter对象，并实例化fw <br>//将字符串写入文件 <br>fw.write("大家好！"); <br>fw.write("本书是《JSP编程技巧》"); <br>fw.write("请多多指教！"); <br>fw.write("email:stride@sina.com"); <br>fw.close(); </p>
<p>FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">\\WriteData.txt</a>"); <br>BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br <br>String Line=br.readLine(); <br>//读取一行数据 <br>out.println(Line + "&lt;br&gt;"); <br>br.close();//关闭BufferedReader对象 <br>fr.close(); <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p><br>将写入文件的数据分行 <br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;将写入文件的数据分行&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("."); <br>FileWriter fw=new FileWriter(path + "<a href="file://WriteData.txt/">\\WriteData.txt</a>"); <br>BufferedWriter bw=new BufferedWriter(fw); <br>bw.write("大家好！"); <br>bw.write("本书是《JSP编程技巧》。"); <br>bw.newLine();//断行 <br>bw.write("请多多指教！"); <br>bw.newLine();//断行 <br>bw.write("email: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#116;&#114;&#105;&#100;&#101;&#64;&#115;&#105;&#110;&#97;&#46;&#99;&#111;&#109;">stride@sina.com</a>"); <br>bw.flush();//将数据更新至文件 <br>fw.close();//关闭文件流 <br>out.println("写入文件内容为：&lt;br&gt;"); <br>FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">\\WriteData.txt</a>"); <br>BufferedReader br=new BufferedReader(fr); <br>String Line=br.readLine();//读取一行数据 <br>while(Line!=null){ <br>out.println(Line + "&lt;br&gt;"); <br>Line=br.readLine(); <br>} <br>fr.close(); <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; </p>
<p>如何将数据追加写入到文件<br>&lt;%@ page contentType="text/html;charset=gb2312"%&gt; <br>&lt;%@ page import="java.io.*"%&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;将写入文件的数据分行&lt;/title&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;% <br>String path=request.getRealPath("."); <br>RandomAccessFile rf=new RandomAccessFile(path + "<a href="file://WriteData.txt%22,%22rw%22);//">\\WriteData.txt","rw");//</a>定义一个类RandomAccessFile的对象，并实例化 <br>rf.seek(rf.length());//将指针移动到文件末尾 <br>rf.writeBytes("\nAppend a line to the file!"); <br>rf.close();//关闭文件流 <br>out.println("写入文件内容为：&lt;br&gt;"); <br>FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">\\WriteData.txt</a>"); <br>BufferedReader br=new BufferedReader(fr);//读取文件的BufferedRead对象 <br>String Line=br.readLine(); <br>while(Line!=null){ <br>out.println(Line + "&lt;br&gt;"); <br>Line=br.readLine(); <br>} <br>fr.close();//关闭文件 <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt;&lt;/I&gt;&lt;/I&gt;&lt;/I&gt;&lt;/I&gt;</p>
<img src ="http://www.blogjava.net/wjywilliam/aggbug/122059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wjywilliam/" target="_blank">wjywilliam</a> 2007-06-05 09:44 <a href="http://www.blogjava.net/wjywilliam/articles/122059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java的IO系统基本应用</title><link>http://www.blogjava.net/wjywilliam/articles/109042.html</link><dc:creator>wjywilliam</dc:creator><author>wjywilliam</author><pubDate>Fri, 06 Apr 2007 16:01:00 GMT</pubDate><guid>http://www.blogjava.net/wjywilliam/articles/109042.html</guid><wfw:comment>http://www.blogjava.net/wjywilliam/comments/109042.html</wfw:comment><comments>http://www.blogjava.net/wjywilliam/articles/109042.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wjywilliam/comments/commentRss/109042.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wjywilliam/services/trackbacks/109042.html</trackback:ping><description><![CDATA[<p><font style="BACKGROUND-COLOR: #ffffff" color=#006400 size=5><strong>Java的IO系统基本应用</strong> </font></p>
<p>&nbsp;</p>
<div class=postText>
<p><strong>1. stream</strong> <strong><br></strong>stream代表的是任何有能力产出数据的数据源，或是任何有能力接收数据的接收源。在Java的IO中，所有的stream（包括Input和Out stream）都包括两种类型：<br>&nbsp;<br>&nbsp;1.1 以字节为导向的stream<br>&nbsp;以字节为导向的stream，表示以字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种类型：<br>&nbsp;1) input　stream：<br>&nbsp;1) ByteArrayInputStream：把内存中的一个缓冲区作为InputStream使用<br>&nbsp;2) StringBufferInputStream：把一个String对象作为InputStream<br>&nbsp;3) FileInputStream：把一个文件作为InputStream，实现对文件的读取操作<br>&nbsp;4) PipedInputStream：实现了pipe的概念，主要在线程中使用<br>&nbsp;5) SequenceInputStream：把多个InputStream合并为一个InputStream<br>&nbsp;2) Out　stream<br>&nbsp;1) ByteArrayOutputStream：把信息存入内存中的一个缓冲区中<br>&nbsp;2) FileOutputStream：把信息存入文件中<br>&nbsp;3) PipedOutputStream：实现了pipe的概念，主要在线程中使用<br>&nbsp;4) SequenceOutputStream：把多个OutStream合并为一个OutStream<br>&nbsp;<br>&nbsp;1.2 以Unicode字符为导向的stream<br>&nbsp;以Unicode字符为导向的stream，表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种类型：<br>&nbsp;1) Input　Stream<br>&nbsp;1) CharArrayReader：与ByteArrayInputStream对应<br>&nbsp;2) StringReader：与StringBufferInputStream对应<br>&nbsp;3) FileReader：与FileInputStream对应<br>&nbsp;4) PipedReader：与PipedInputStream对应<br>&nbsp;2) Out　Stream<br>&nbsp;1) CharArrayWrite：与ByteArrayOutputStream对应<br>&nbsp;2) StringWrite：无与之对应的以字节为导向的stream<br>&nbsp;3) FileWrite：与FileOutputStream对应<br>&nbsp;4) PipedWrite：与PipedOutputStream对应<br>&nbsp;以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同，字是在操作时的导向不同。如CharArrayReader：和ByteArrayInputStream的作用都是把内存中的一个缓冲区作为InputStream使用，所不同的是前者每次从内存中读取一个字节的信息，而后者每次从内存中读取一个字符。<br>&nbsp;<br>&nbsp;1.3 两种不现导向的stream之间的转换<br>&nbsp;InputStreamReader和OutputStreamReader：把一个以字节为导向的stream转换成一个以字符为导向的stream。<br>&nbsp;<br>&nbsp;<strong>2. stream添加属性<br></strong>&nbsp;<br>&nbsp;2.1 &#8220;为stream添加属性&#8221;的作用<br>&nbsp;运用上面介绍的Java中操作IO的API，我们就可完成我们想完成的任何操作了。但通过FilterInputStream和FilterOutStream的子类，我们可以为stream添加属性。下面以一个例子来说明这种功能的作用。<br>&nbsp;如果我们要往一个文件中写入数据，我们可以这样操作：<br>&nbsp;FileOutStream fs = new FileOutStream(&#8220;test.txt&#8221;);<br>&nbsp;然后就可以通过产生的fs对象调用write()函数来往test.txt文件中写入数据了。但是，如果我们想实现&#8220;先把要写入文件的数据先缓存到内存中，再把缓存中的数据写入文件中&#8221;的功能时，上面的API就没有一个能满足我们的需求了。但是通过FilterInputStream和FilterOutStream的子类，为FileOutStream添加我们所需要的功能。<br>&nbsp;<br>&nbsp;2.2 FilterInputStream的各种类型<br>&nbsp;<br>&nbsp;2.2.1 用于封装以字节为导向的InputStream<br>&nbsp;1) DataInputStream：从stream中读取基本类型（int、char等）数据。<br>&nbsp;2) BufferedInputStream：使用缓冲区<br>&nbsp;3) LineNumberInputStream：会记录input stream内的行数，然后可以调用getLineNumber()和setLineNumber(int)<br>&nbsp;4) PushbackInputStream：很少用到，一般用于编译器开发<br>&nbsp;<br>&nbsp;2.2.2 用于封装以字符为导向的InputStream<br>&nbsp;1) 没有与DataInputStream对应的类。除非在要使用readLine()时改用BufferedReader，否则使用DataInputStream<br>&nbsp;2) BufferedReader：与BufferedInputStream对应<br>&nbsp;3) LineNumberReader：与LineNumberInputStream对应<br>&nbsp;4) PushBackReader：与PushbackInputStream对应<br>&nbsp;<br>&nbsp;2.3 FilterOutStream的各种类型<br>&nbsp;<br>&nbsp;2.2.3 用于封装以字节为导向的OutputStream<br>&nbsp;1) DataIOutStream：往stream中输出基本类型（int、char等）数据。<br>&nbsp;2) BufferedOutStream：使用缓冲区<br>&nbsp;3) PrintStream：产生格式化输出<br>&nbsp;<br>&nbsp;2.2.4 用于封装以字符为导向的OutputStream<br>&nbsp;1) BufferedWrite：与对应<br>&nbsp;2) PrintWrite：与对应<br>&nbsp;<br><strong>&nbsp;3. RandomAccessFile<br><br></strong>&nbsp;1) 可通过RandomAccessFile对象完成对文件的读写操作<br>&nbsp;2) 在产生一个对象时，可指明要打开的文件的性质：r，只读；w，只写；rw可读写<br>&nbsp;3) 可以直接跳到文件中指定的位置<br>&nbsp;<br><strong>&nbsp;4. I/O应用的一个例子<br></strong><br>&nbsp;<font color=#0000ff>import java.io.*;<br>&nbsp;public class TestIO{<br>&nbsp;public static void main(String[] args)<br>&nbsp;throws IOException{<br>&nbsp;<font color=#006400>//1.以行为单位从一个文件读取数据</font><br>&nbsp;BufferedReader in = <br>&nbsp;new BufferedReader(<br>&nbsp;new FileReader("F:\\nepalon\\TestIO.java"));<br>&nbsp;String s, s2 = new String();<br>&nbsp;while((s = in.readLine()) != null)<br>&nbsp;s2 += s + "\n";<br>&nbsp;in.close();<br>&nbsp;<br>&nbsp;<font color=#008000>//1b. 接收键盘的输入<br></font>&nbsp;BufferedReader stdin = <br>&nbsp;new BufferedReader(<br>&nbsp;new InputStreamReader(System.in));<br>&nbsp;System.out.println("Enter a line:");<br>&nbsp;System.out.println(stdin.readLine());<br>&nbsp;<br><font color=#006400>&nbsp;//2. 从一个String对象中读取数据</font><br>&nbsp;StringReader in2 = new StringReader(s2);<br>&nbsp;int c;<br>&nbsp;while((c = in2.read()) != -1)<br>&nbsp;System.out.println((char)c);<br>&nbsp;in2.close();<br>&nbsp;<br><font color=#006400>&nbsp;//3. 从内存取出格式化输入</font><br>&nbsp;try{<br>&nbsp;DataInputStream in3 = <br>&nbsp;new DataInputStream(<br>&nbsp;new ByteArrayInputStream(s2.getBytes()));<br>&nbsp;while(true)<br>&nbsp;System.out.println((char)in3.readByte()); <br>&nbsp;}<br>&nbsp;catch(EOFException e){<br>&nbsp;System.out.println("End of stream");<br>&nbsp;}<br>&nbsp;<br><font color=#006400>&nbsp;//4. 输出到文件<br></font>&nbsp;try{<br>&nbsp;BufferedReader in4 =<br>&nbsp;new BufferedReader(<br>&nbsp;new StringReader(s2));<br>&nbsp;PrintWriter out1 =<br>&nbsp;new PrintWriter(<br>&nbsp;new BufferedWriter(<br>&nbsp;new FileWriter("F:\\nepalon\\ TestIO.out")));<br>&nbsp;int lineCount = 1;<br>&nbsp;while((s = in4.readLine()) != null)<br>&nbsp;out1.println(lineCount++ + "：" + s);<br>&nbsp;out1.close();<br>&nbsp;in4.close();<br>&nbsp;}<br>&nbsp;catch(EOFException ex){<br>&nbsp;System.out.println("End of stream");<br>&nbsp;}<br>&nbsp;<br><font color=#006400>&nbsp;//5. 数据的存储和恢复</font><br>&nbsp;try{<br>&nbsp;DataOutputStream out2 = <br>&nbsp;new DataOutputStream(<br>&nbsp;new BufferedOutputStream(<br>&nbsp;new FileOutputStream("F:\\nepalon\\ Data.txt")));<br>&nbsp;out2.writeDouble(3.1415926);<br>&nbsp;out2.writeChars("\nThas was pi:writeChars\n");<br>&nbsp;out2.writeBytes("Thas was pi:writeByte\n");<br>&nbsp;out2.close();<br>&nbsp;DataInputStream in5 =<br>&nbsp;new DataInputStream(<br>&nbsp;new BufferedInputStream(<br>&nbsp;new FileInputStream("F:\\nepalon\\ Data.txt")));<br>&nbsp;BufferedReader in5br =<br>&nbsp;new BufferedReader(<br>&nbsp;new InputStreamReader(in5));<br>&nbsp;System.out.println(in5.readDouble());<br>&nbsp;System.out.println(in5br.readLine());<br>&nbsp;System.out.println(in5br.readLine());<br>&nbsp;}<br>&nbsp;catch(EOFException e){<br>&nbsp;System.out.println("End of stream");<br>&nbsp;}<br>&nbsp;<br><font color=#006400>&nbsp;//6. 通过RandomAccessFile操作文件<br></font>&nbsp;RandomAccessFile rf =<br>&nbsp;new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");<br>&nbsp;for(int i=0; i&lt;10; i++)<br>&nbsp;rf.writeDouble(i*1.414);<br>&nbsp;rf.close();<br>&nbsp;<br>&nbsp;rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");<br>&nbsp;for(int i=0; i&lt;10; i++)<br>&nbsp;System.out.println("Value " + i + "：" + rf.readDouble());<br>&nbsp;rf.close();<br>&nbsp;<br>&nbsp;rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");<br>&nbsp;rf.seek(5*8);<br>&nbsp;rf.writeDouble(47.0001);<br>&nbsp;rf.close();<br>&nbsp;<br>&nbsp;rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");<br>&nbsp;for(int i=0; i&lt;10; i++)<br>&nbsp;System.out.println("Value " + i + "：" + rf.readDouble());<br>&nbsp;rf.close();<br>&nbsp;}<br>&nbsp;}<br></font>&nbsp;<br>&nbsp;<strong>关于代码的解释（以区为单位）：</strong><br>&nbsp;1区中，当读取文件时，先把文件内容读到缓存中，当调用in.readLine()时，再从缓存中以字符的方式读取数据（以下简称&#8220;缓存字节读取方式&#8221;）。<br>&nbsp;1b区中，由于想以缓存字节读取方式从标准IO（键盘）中读取数据，所以要先把标准IO（System.in）转换成字符导向的stream，再进行BufferedReader封装。<br>&nbsp;2区中，要以字符的形式从一个String对象中读取数据，所以要产生一个StringReader类型的stream。<br>&nbsp;4区中，对String对象s2读取数据时，先把对象中的数据存入缓存中，再从缓冲中进行读取；对TestIO.out文件进行操作时，先把格式化后的信息输出到缓存中，再把缓存中的信息输出到文件中。<br>&nbsp;5区中，对Data.txt文件进行输出时，是先把基本类型的数据输出屋缓存中，再把缓存中的数据输出到文件中；对文件进行读取操作时，先把文件中的数据读取到缓存中，再从缓存中以基本类型的形式进行读取。注意in5.readDouble()这一行。因为写入第一个writeDouble()，所以为了正确显示。也要以基本类型的形式进行读取。<br>&nbsp;6区是通过RandomAccessFile类对文件进行操作。</p>
</div>
<img src ="http://www.blogjava.net/wjywilliam/aggbug/109042.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wjywilliam/" target="_blank">wjywilliam</a> 2007-04-07 00:01 <a href="http://www.blogjava.net/wjywilliam/articles/109042.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>眀海棠文集之数据格式化1.0</title><link>http://www.blogjava.net/wjywilliam/articles/109039.html</link><dc:creator>wjywilliam</dc:creator><author>wjywilliam</author><pubDate>Fri, 06 Apr 2007 15:56:00 GMT</pubDate><guid>http://www.blogjava.net/wjywilliam/articles/109039.html</guid><wfw:comment>http://www.blogjava.net/wjywilliam/comments/109039.html</wfw:comment><comments>http://www.blogjava.net/wjywilliam/articles/109039.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wjywilliam/comments/commentRss/109039.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wjywilliam/services/trackbacks/109039.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 眀海棠文集之数据格式化1.0 &nbsp; java.text 包允许通过与特定语言无关的方式格式化文本消息、日期和数值。 1. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据格式化相关类介绍                                     类                          ...&nbsp;&nbsp;<a href='http://www.blogjava.net/wjywilliam/articles/109039.html'>阅读全文</a><img src ="http://www.blogjava.net/wjywilliam/aggbug/109039.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wjywilliam/" target="_blank">wjywilliam</a> 2007-04-06 23:56 <a href="http://www.blogjava.net/wjywilliam/articles/109039.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>