﻿<?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-贫以智为贵,富以仁为贵.-文章分类-系统架构</title><link>http://www.blogjava.net/LeungXin/category/16258.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 10 Sep 2007 02:22:22 GMT</lastBuildDate><pubDate>Mon, 10 Sep 2007 02:22:22 GMT</pubDate><ttl>60</ttl><item><title>如何选择抽象基类与接口</title><link>http://www.blogjava.net/LeungXin/articles/143896.html</link><dc:creator>梁昕</dc:creator><author>梁昕</author><pubDate>Mon, 10 Sep 2007 02:12:00 GMT</pubDate><guid>http://www.blogjava.net/LeungXin/articles/143896.html</guid><wfw:comment>http://www.blogjava.net/LeungXin/comments/143896.html</wfw:comment><comments>http://www.blogjava.net/LeungXin/articles/143896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/LeungXin/comments/commentRss/143896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/LeungXin/services/trackbacks/143896.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt"><strong><font color="#ff6600">抽象基类与接口，共性与个性的选择</font></strong> </span>
<p><span style="font-size: 12pt">JAVA抽象基类(Abstract Class)和接口(Interface)都实现了面向对象中的继承机制，它们通过定义抽象方法匀实现了对继承类的<span style="color: #0820ce">功能上的约束</span>，那么在如何在恰当的场景选择恰当的继承机制是我们在设计中经常会遇到的问题，我们先来对比两者之间的区别与联系。 </span></p>
<p><span style="font-size: 9pt"><strong><span style="font-size: 12pt">相同点 </span></strong></span></p>
<ul>
    <li><span style="font-size: 9pt"><span style="font-size: 12pt">都可以被继承。 </span></span>
    <li><span style="font-size: 9pt"><span style="font-size: 12pt">本身都不能被实例化 </span></span></li>
</ul>
<p><span style="font-size: 9pt"><strong><span style="font-size: 12pt">不同点 </span></strong></span></p>
<ul>
    <li><span style="font-size: 9pt"><span style="font-size: 12pt">抽象类是一个不完整的类，需要进一步细化；而接口只是一个行为上的规范。<strong> </strong></span></span>
    <li><span style="font-size: 9pt"><span style="font-size: 12pt">抽象基类不能实现多继承，而接口可以实现多继承。 </span></span>
    <li><span style="font-size: 12pt"><span style="font-size: 9pt"><span style="font-size: 12pt">抽象基类可以定义字段、属性、包含有实现的方法。接口可以定义字段、索引器、事件但不能定义字段和包含实现的方法。</span>&nbsp;</span>&nbsp;&nbsp;&nbsp; </span></li>
</ul>
<p><span style="font-size: 9pt"><strong><span style="font-size: 12pt">共性、个性与选择 </span></strong></span></p>
<p><span style="font-size: 9pt"><span style="font-size: 12pt"><span>有的书上写到</span>JAVA<span>中推荐使用接口（</span>Interface）<span>来替代抽象基类（</span>Abstract Class）<span>，并强调使用接口的诸多好处，这点我不敢苟同，从上面列表中看来，两者之间还是存在不少差异的，而这种差异的存在性必然决定了适用场景的不同，例如在抽象基类中可以为部分方法提供默认的实现，从而避免在子类中重复实现它们，提高代码的可重用性，这是抽象类的优势所在；而接口中只能包含抽象方法。<span style="color: #0820ce">至于何时使用抽象基类何时使用接口关键还是取决于用户是如何看待继承类之间的联系的，用户更加关心的是它们之间的个性差异还是它们之间的共性联系。</span>举个生活中的例子加以说明。 </span></span></span></p>
<p><span style="font-size: 9pt"><span style="font-size: 12pt">如果给你三个对象分别是人、鱼、青蛙，让你为他们设计个基类来概括它们之间的联系，那么首先给你的感觉肯定是它们个体间的差异性较大，很难抽象出共性，然而若让你概括他们行为之间的共性，你可能想了想会意识到他们都会游泳，只不过是游泳方式迥异。那么这时你就应当考虑使用接口而不是抽象基类，原因有三条： </span></span><span style="font-size: 9pt; color: #0820ce"><span style="font-size: 12pt"></p>
<ol>
    <li><span style="color: #0820ce"><span style="font-size: 12pt">个性大于共性。 </span></span>
    <li><span style="color: #0820ce"><span style="font-size: 12pt">差异较大的个性间具有某些相同的行为。 </span></span>
    <li><span style="font-size: 12pt; color: #0820ce"><span style="font-size: 12pt">相同行为的实现方式有较大区别。 </span></span></li>
    </span></span></ol>
    <p><span style="font-size: 9pt"><span style="font-size: 14pt"><span style="font-size: 12pt"><span style="font-size: 12pt">设计为： 好，这时再给你三个对象，分别是鲫鱼、鲤鱼、金鱼，仍然让你设计基类来概括它们之间的联系，那么你第一个意识到的肯定是它们都属于鱼类，其次是他们游泳的方式可能稍有差异，这时就应当使用抽象基<span style="font-size: 12pt">类而不是接口，对比着上面的例子，原因也有三条： </span></span></span></span></span></p>
    <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="font-size: 12pt"><span style="color: #008080">1</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">interface</span></span><span style="font-size: 12pt"><span style="color: #000000"> ISwim<br />
    </span><span style="color: #008080">2</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">3</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim();<br />
    </span><span style="color: #008080">4</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">5</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">6</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> Person : ISwim<br />
    </span><span style="color: #008080">7</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">8</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">9</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">10</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swimming in person's style.</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">11</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">12</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">13</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">14</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> Frog : ISwim<br />
    </span><span style="color: #008080">15</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">16</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">17</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">18</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swimming in frog's style.</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">19</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">20</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">21</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">22</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> Fish : ISwim<br />
    </span><span style="color: #008080">23</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">24</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">25</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">26</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swimming in fish's style.</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">27</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">28</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></span></div>
    <p></p>
    <ol>
        <li><span style="font-size: 9pt; color: #0820ce"><span style="font-size: 12pt">共性大于个性 </span></span>
        <li><span style="font-size: 9pt; color: #0820ce"><span style="font-size: 12pt">共性相同的个体间必然具有相同的属性与行为。 </span></span>
        <li><span style="font-size: 9pt; color: #0820ce"><span style="font-size: 12pt">相同行为的实现方式具有一定区别。 </span></span></li>
    </ol>
    <p><span style="font-size: 12pt"><span style="font-size: 9pt">设计为： </span><span style="font-size: 9pt"><strong>总结： </strong></span></span></p>
    <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="font-size: 12pt"><span style="color: #008080">1</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">abstract</span><span style="color: #000000"> </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> Fish<br />
    </span><span style="color: #008080">2</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">3</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">abstract</span><span style="color: #000000"> </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim();<br />
    </span><span style="color: #008080">4</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">5</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">6</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> 鲫鱼 : Fish<br />
    </span><span style="color: #008080">7</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">8</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">override</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">9</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">10</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swim like a 鲫鱼</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">11</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">12</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">13</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">14</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> 鲤鱼 : Fish<br />
    </span><span style="color: #008080">15</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">16</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">override</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">17</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">18</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swim like a 鲤鱼</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">19</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">20</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">21</span> </span><span style="color: #000000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">22</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">class</span></span><span style="font-size: 12pt"><span style="color: #000000"> 金鱼 : Fish<br />
    </span><span style="color: #008080">23</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">24</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">override</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span></span><span style="font-size: 12pt"><span style="color: #000000"> Swim()<br />
    </span><span style="color: #008080">25</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
    </span><span style="color: #008080">26</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">Swim like a 金鱼</span></span><span style="color: #008000"><br />
    </span><span style="font-size: 12pt"><span style="color: #008080">27</span> </span><span style="font-size: 12pt"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
    </span><span style="color: #008080">28</span> <span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></span></div>
    <p></p>
    <p><span style="font-size: 9pt"><span style="font-size: 12pt"><span>观察在使用接口或是使用抽象基类的几条理由中，第三条理由其实是一样的，它所描述的是面向对象中多态的概念，即通过覆盖父类的方法来实现，在运行时根据传递的对象引用，来调用相应的方法。第二条理由开始产生分歧，接口更加强调了继承对象间具有相同的行为，而抽象类同时还强调了继承对象间具有相同的属性。而真正将接口与抽象基类区分开的则是理由一，归纳如下：</span><span> </span></span></span></p>
    <ol>
        <li><span style="font-size: 9pt; color: #0820ce"><span style="font-size: 12pt">当在差异较大的对象间寻求功能上的共性时，使用接口。</span></span>
        <li><span style="font-size: 14pt"><span style="font-size: 9pt; color: #0820ce">当在共性较多的对象间寻求功能上的差异时，使用抽象基类。</span> </span></li>
    </ol>
    <p><span style="font-size: 12pt"><strong>抽象类和接口区别总结</strong></span></p>
    <p><span style="font-size: 12pt">　1.类是对对象的抽象，可以把抽象类理解为把类当作对象，抽象成的类　 <br />
    　　接口只是一个行为的规范或规定，微软的自定义接口总是后带able字段，证明其是表述一类类&#8220;我能做。。。&#8221;抽象类更多的是定义在一系列紧密相关的类间，而接口大多数是关系疏松但都实现某一功能的类中　 <br />
    　2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;　　 <br />
    　3.一个类一次可以实现若干个接口,但是只能扩展一个父类　　 <br />
    　4.接口可以用于支持回调,而继承并不具备这个特点.　　 <br />
    　5.抽象类不能被密封。　 <br />
    　6.抽象类实现的具体方法默认为虚的，但实现接口的类中的接口方法却默认为非虚的，当然您也可以声明为虚的。<br />
    　7.（接口）与非抽象类类似，抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是，允许抽象类将接口方法映射到抽象方法上。　 <br />
    　8.抽象类实现了oop中的一个原则，把可变的与不可变的分离。抽象类和接口就是定义为不可变的，而把可变的座位子类去实现。　 <br />
    　9.好的接口定义应该是具有专一功能性的，而不是多功能的，否则造成接口污染。如果一个类只是实现了这个接口的中一个功能，而不得不去实现接口中的其他方法，就叫接口污染。　 <br />
    　10.尽量避免使用继承来实现组建功能，而是使用黑箱复用，即对象组合。因为继承的层次增多，造成最直接的后果就是当你调用这个类群中某一类，就必须把他们全部加载到栈中！后果可想而知.　 <br />
    　11.如果抽象类实现接口，则可以把接口中方法映射到抽象类中作为抽象方法而不必实现，而在抽象类的子类中实现接口中方法　 <br />
    　　 如果预计要创建组件的多个版本，则创建抽象类。抽象类提供简单的方法来控制组件版本。如果创建的功能将在大范围的全异对象间使用，则使用接口。如果要设计小而简练的功能块，则使用接口。如果要设计大的功能单元，则使用抽象类。　　 <br />
    　　 如果要在组件的所有实现间提供通用的已实现功能，则使用抽象类。<br />
    <br />
    <br />
    抽象类：<br />
    　　a.包含一个或多个抽象方法或属性的类必须定义为抽象类 <br />
    　　b.继承抽象类的派生类必须实现抽象类的所有抽象方法或属性,否則該派生类也必是抽象类,至到完全实现为止. <br />
    　　c.抽象类必须是公共的(public). <br />
    　　d.抽象类不存在对象实例,但可以申明引用变量.另外抽象类中可以有非抽象方法,供派生类调用. <br />
    <br />
    接　口：<br />
    　　1.接口中定义抽象的方法,属性,索引,事件 <br />
    　　2.接口必须由类來实现,故其只能是默认public的,不可顯式申明,不能申明为 static <br />
    　　3.实现接口的类必须完全实现接口中的所有的方法属性,索引,事件,不能只实现一部分 <br />
    　　4.一个类只能继承一个基类,但可以实现多个接口,其中继承的基类必须放在最前面,然后是接口,它們用逗號分開. <br />
    <br />
    何时用抽象类，何时用接口？<br />
    <br />
    ※ 如果预计要创建组件的多个版本，则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类，所有继承类都随更改自动更新。另一方面，接口一旦创建就不能更改。如果需要接口的新版本，必须创建一个全新的接口。<br />
    ※ 如果创建的功能将在大范围的全异对象间使用，则使用接口。抽象类应主要用于关系密切的对象，而接口最适合为不相关的类提供通用功能。<br />
    ※ 如果要设计小而简练的功能块，则使用接口。如果要设计大的功能单元，则使用抽象类。<br />
    ※ 如果要在组件的所有实现间提供通用的已实现功能，则使用抽象类。抽象类允许部分实现类，而接口不包含任何成员的实现。<br />
    <br />
    1、接口中只能有方法，不能有字段；抽象类中即可以有方法，也可以有属性和字段； <br />
    2、接口中的方法不需要实现，而抽象类中可以有实现了的方法； <br />
    3、接口在一定程度上可以代替多继承。 <br />
    4、实现接口，也就意味着必须实现接口中的所有方法。如果继承抽象类的子类还是抽象类，则可以只实现部分方法。 <br />
    5、接口和抽象类都不被实例化成对象。<br />
    <br />
    首先要明确抽象类和接口使用上的区别，类只能单一的继承，如果一个类的方法只让其派生类实现，那么就可以用抽象类，如果方法是被多个类使用，那么就使用接口。 <br />
    <br />
    </p>
    <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000">例如：&nbsp;<br />
    　使用抽象类：&nbsp;<br />
    　</span><span style="color: #0000ff">abstract</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;A&nbsp;<br />
    　{&nbsp;<br />
    　　</span><span style="color: #0000ff">abstract</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;put();&nbsp;<br />
    　}&nbsp;<br />
    <br />
    　</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;B&nbsp;:&nbsp;A&nbsp;<br />
    　{&nbsp;<br />
    　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;put()&nbsp;<br />
    　　{&nbsp;<br />
    　　　　Console.WriteLine(</span><span style="color: #000000">"</span><span style="color: #000000">B</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;<br />
    　　}&nbsp;<br />
    　}&nbsp;<br />
    <br />
    　</span><span style="color: #008000">//</span><span style="color: #008000">-----------------------------------------&nbsp;</span><span style="color: #008000"><br />
    </span><span style="color: #000000"><br />
    　使用接口：&nbsp;<br />
    　</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;Ia&nbsp;<br />
    　{&nbsp;<br />
    　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;put();&nbsp;<br />
    　}&nbsp;<br />
    　<br />
    　</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;A&nbsp;:&nbsp;Ia&nbsp;<br />
    　{&nbsp;<br />
    　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;put()&nbsp;<br />
    　　{&nbsp;<br />
    　　　　Console.WriteLine(</span><span style="color: #000000">"</span><span style="color: #000000">A</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;<br />
    　　}&nbsp;<br />
    　}&nbsp;<br />
    　<br />
    　</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;B&nbsp;:&nbsp;Ia&nbsp;<br />
    　{&nbsp;<br />
    　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;put()&nbsp;<br />
    　　{&nbsp;<br />
    　　　　Console.WriteLine(</span><span style="color: #000000">"</span><span style="color: #000000">B</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;<br />
    　　}&nbsp;　<br />
    　}<br />
    </span></div>
    <p><br />
    </span></p>
<img src ="http://www.blogjava.net/LeungXin/aggbug/143896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/LeungXin/" target="_blank">梁昕</a> 2007-09-10 10:12 <a href="http://www.blogjava.net/LeungXin/articles/143896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用struts+spring+hibernate 组装web应用</title><link>http://www.blogjava.net/LeungXin/articles/74821.html</link><dc:creator>梁昕</dc:creator><author>梁昕</author><pubDate>Thu, 12 Oct 2006 09:08:00 GMT</pubDate><guid>http://www.blogjava.net/LeungXin/articles/74821.html</guid><wfw:comment>http://www.blogjava.net/LeungXin/comments/74821.html</wfw:comment><comments>http://www.blogjava.net/LeungXin/articles/74821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/LeungXin/comments/commentRss/74821.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/LeungXin/services/trackbacks/74821.html</trackback:ping><description><![CDATA[
		<span id="ArticleContent1_ArticleContent1_lblContent">
				<span class="postbody">
						<font face="宋体">其实，就算用Java建造一个不是很烦琐的web应用，也不是件轻松的事情。 在构架的一开始就有很多事情要考虑。 从高处看，摆在开发者面前有很多问题：要考虑是怎样建立用户接口？在哪里处理业务逻辑？ 怎样持久化的数据。 而这三层构架中，每一层都有他们要仔细考虑的。 各个层该使用什么技术？ 怎样的设计能松散耦合还能灵活改变？ 怎样替换某个层而不影响整体构架？应用程序如何做各种级别的业务处理（比如事务处理）？ <br /><br /><br /><br />构架一个Web应用需要弄明白好多问题。 幸运的是，已经有不少开发者已经遇到过这类问题，并且建立了处理这类问题的框架。 一个好框架具备以下几点： 减轻开发者处理复杂的问题的负担（“不重复发明轮子”）； 内部有良好的扩展； 并且有一个支持它的强大的用户团体。 好的构架一般有针对性的处理某一类问题，并且能将它做好（Do One Thing well）。 然而，你的程序中有几个层可能需要使用特定的框架，已经完成的UI(用户接口) 并不代表你也可以把你的业务逻辑和持久逻辑偶合到你的UI部分。 举个例子， 你不该在一个Controller(控制器)里面写JDBC代码作为你的业务逻辑， 这不是控制器应该提供的。 一个UI 控制器应该委派给其它给在UI范围之外的轻量级组件。 好的框架应该能指导代码如何分布。 更重要的是，框架能把开发者从编码中解放出来，使他们能专心于应用程序的逻辑（这对客户来说很重要）。 <br /><br /><br /><br />这篇文章将讨论怎样结合几种著名的框架来使得你的应用程序做到松弛耦合。 <br /><br />如何建立你的架构，并且怎样让你的各个应用层保持一致。？如何整合框架以便让每个层在以一种松散偶合的方式彼此作用而不用管低层的技术细节？这对我们来说真是一种挑战。 这里讨论一个整合框架的策略( 使用3 种受欢迎的开源框架) ：表示层我们用Struts； 业务层我们用Spring；而持久层则用Hibernate。 你也可以用其他FrameWork替换只要能得到同样的效果。 见图1 （框架组合示意图） <br /><br /><img src="http://www.onjava.com/onjava/2004/04/07/graphics/wiring.gif" border="0" /><br /><br /><span style="FONT-WEIGHT: bold">应用程序的分层</span><br /><br />大部分的Web应用在职责上至少能被分成4层。 这四层是：presentation（描述），persistence（持久），business（业务）和domain model（域模块）。每个层在处理程序上都应该有一项明确的责任, 而不应该在功能上与其它层混合，并且每个层要与其它层分开的，但要给他们之间放一个通信接口。 我们就从介绍各个层开始，讨论一下这些层应该提供什么，不应该提供什么。 <br /><br /><br /><br /><span style="FONT-WEIGHT: bold">表示层(The Presentation Layer) </span><br /><br />一般来讲，一个典型的Web应用的的末端应该是表示层。 很多Java发者也理解Struts所提供的。 象业务逻辑之类的被打包到org.apache.struts.Action.， 因此，我们很赞成使用Struts这样的框架。 <br /><br /><br /><br />下面是Struts所负责的： <br /><br />* 管理用户的请求,做出相应的响应。 <br /><br />* 提供一个Controller ,委派调用业务逻辑和其它上层处理。 <br /><br />* 处理异常，抛给Struts Action <br /><br />* 为显示提供一个模型 <br /><br />* UI验证。 <br /><br /><br /><br />以下条款，不该在Struts显示层的编码中经常出现。 它们与显示层无关的。 <br /><br />* 直接的与数据库通信，例如JDBC调用。 <br /><br />* 与你应用程序相关联的业务逻辑以及校验。 <br /><br />* 事物管理。 <br /><br />在表示层引入这些代码，则会带来高偶合和麻烦的维护。 <br /><br /><br /><br /><br /><br /><span style="FONT-WEIGHT: bold">持久层(The Persistence Layer)</span><br /><br />典型的Web应用的另一个末端是持久层。这里通常是程序最容易失控的地方。开发者总是低估构建他们自己的持久框架的挑战性。系统内部的持续层不但需要大量调试时间，而且还经常缺少功能使之变得难以控制，这是持久层的通病。 还好有几个ORM开源框架很好的解决了这类问题。尤其是Hibernate。 Hibernate为java提供了OR持久化机制和查询服务, 它还给已经熟悉SQL和JDBC API 的Java开发者一个学习桥梁，他们学习起来很方便。 Hibernate的持久对象是基于POJO和Java collections。此外，使用Hibernate并不妨碍你正在使用的IDE。 <br /><br /><br /><br />请看下面的条目，你在持久层编码中需要了解的。 <br /><br />* 查询对象的相关信息的语句。 Hibernate通过一个OO查询语言（HQL）或者正则表达的API来完成查询。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。 你需要学习一些新的HQL语言； 不管怎样，他们容易理解而文档也做的很好。 HQL是一种对象查询的自然语言，花很小的代价就能学习它。 <br /><br />* 如何存储，更新，删除数据库记录。 <br /><br />* 象Hibernate这类的高级ORM框架支持大部分主流数据库，并且他们支持 Parent/child关系，事物处理，继承和多态。 <br /><br /><br /><br /><span style="FONT-WEIGHT: bold">业务层（The Business Layer）</span><br /><br />一个典型Web应用的中间部分是业务层或者服务层。 从编码的视角来看，这层是最容易被忽视的一层。 而我们却往往在UI层或持久层周围看到这些业务处理的代码，这其实是不正确的，因为它导致了程序代码的紧密偶合，这样一来，随着时间推移这些代码很难维护。幸好，针对这一问题有好几种Frameworks存在。 最受欢迎的两个框架是Spring和PicoContainer。 这些为也被称为microcontainers，他们能让你很好的把对象搭配起来。 这两个框架都着手于‘依赖注射’(dependency injection)(还有我们知道的‘控制反转’Inversion of Control=IoC)这样的简单概念。 这篇文章将关注于Spring的注射（译注：通过一个给定参数的Setter方法来构造Bean,有所不同于Factory）, Spring还提供了Setter Injection(type2)，Constructor Injection(type3)等方式供我们选择。 Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handler（事物管理控制）、Object Factoris(对象工厂)、service objects（服务组件）——都通过XML来配置联系起来。 <br /><br /><br /><br />后面我们会举个例子来揭示一下Spring 是怎样运用这些概念。 <br /><br />业务层所负责的如下： <br /><br />* 处理应用程序的 业务逻辑和业务校验 <br /><br />* 管理事物 <br /><br />* 允许与其它层相互作用的接口 <br /><br />* 管理业务层级别的对象的依赖。 <br /><br />* 在显示层和持久层之间增加了一个灵活的机制，使得他们不直接的联系在一起。 <br /><br />* 通过揭示 从显示层到业务层之间的Context来得到business services。 <br /><br />* 管理程序的执行（从业务层到持久层）。 <br /><br /><br /><br /><br /><br /><span style="FONT-WEIGHT: bold">域模块层（The Domain Model Layer ）</span><br />既然我们致力于的是一个不是很复杂的Web的应用， 我们需要一个对象集合，让它在不同层之间移动的。 域模块层由实际需求中的业务对象组成 比如, OrderLineItem , Product等等。 开发者在这层 不用管那些DTOs，仅关注domain object即可。 例如，Hibernate允许你将数据库中的信息存放入对象（domain objects），这样你可以在连接断开的情况下把这些数据显示到UI层。 而那些对象也可以返回给持续层，从而在数据库里更新。 而且，你不必把对象转化成DTOs（这可能似的它在不同层之间的在传输过程中丢失），这个模型使得Java开发者能很自然运用OO，而不需要附加的编码。 <br /><br />一个简单例子 <br /><br /><br /><br />既然我们已经从全局上理解这些组件。 现在就让我们开始实践吧。 我们还是用 Struts，Spring 和Hibernate。这三个框架已经被描述够多了，这里就不重复介绍了。 这篇文章举例指导你如何使用这三个框架整合开发, 并向你揭示 一个请求是如何贯穿于各个层的。（从用户的加入一个Order到数据库，显示；进而更新、删除）。 <br /><br /><br /><br />从这里可以下载到程序程序原代码（</font>
						<a class="postlink" href="http://www.onjava.com/onjava/2004/04/07/examples/wiring.zip" target="_blank">
								<font face="宋体" color="#006699">download</font>
						</a>
						<font face="宋体">） <br /><br />既然每个层是互相作用的，我们就先来创建domain objects。首先，我们要在这些Object中要确定那些是需要持久化的，哪些是提供给business logic，那些是显示接口的设计。 下一步，我们将配置我们的持久层并且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后，我们将 使用Spring把这些连接起来。 最后，我们提供给Spring一个持久层，从这个持久层里我们可以知道它是如何与业务逻辑层（business service layer）通信的，以及它是怎样处理其他层抛出的异常的。。 <br /><br /><br /><br /><span style="FONT-WEIGHT: bold">域对象层（Domain Object Layer）</span><br /><br /><br />这层是编码的着手点，我们的编码就从这层开始。 例子中Order 与OrderItem 是一个One—To—Many的关系。 下面就是Domain Object Layer的两个对象： <br /><br /><br /><br />· com.meagle.bo.Order.java: 包含了一个Order的概要信息 <br /><br />· com.meagle.bo.OrderLineItem.java: 包含了Order的详细信息 <br /><br />好好考虑怎你的package命名,这反应出了你是怎样分层的。 例如 domain objects在程序中可能打包在com.meagle.bo内。 更详细一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包，而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions的 持久对象（presentation classes） 应该分别放在 com.meagle.action和com.meagle.forms包。 准确的给包命名使得你的classes很好分割并且易于维护，并且在你添加新的classes时，能使得程序结构上保持上下一致。 <br /><br /><span style="FONT-WEIGHT: bold">持久层的配置（Persistence Layer Configuration）</span><br /><br />建立Hibernate的持久层 需要好几个步骤。 第一步让我们把BO持久化。 既然Hibernate是通过POJO工作的， 因此Order和 OrderLineItem对象需要给所有的fileds 加上getter,setter方法。 Hibernate通过XML文件来映射(OR)对象，以下两个xml文件分别映射了Order 和OrderItem对象。（这里有个叫XDoclet工具可以自动生成你的XML影射文件） <br /><br />- Order.hbm.xml <br />- OrderLineItem.hbm.xml <br /><br />你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文件。Hibernate的 [urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程序 应该与哪个数据库通信，该使用哪个连接池或使用了DataSource， 应该加载哪些持久对象。而</font>
						<a class="postlink" href="http://www.hibernate.org/hib_docs/api/net/sf/hibernate/Session.html" target="_blank">
								<font face="宋体" color="#006699">Session</font>
						</a>
						<font face="宋体">接口是用来完成Selecting，Saving，Delete和Updating这些操作。 后面的我们将讲述SessionFactory和Session是怎样设置的。 <br /><br /><span style="FONT-WEIGHT: bold">业务层的配置（Business Layer Configuration）</span><br /><br />既然我们已经有了domain objects，接下来我们就要business service objects了，用他们来执行程序的logic,调用持久层，得到UI层的requests,处理transactions，并且控制exceptions。 为了将这些连接起来并且易于管理，我们将使用面向方面的 SpringFramework。 Spring 提供了 控制倒置（inversion of control 0==IoC)和注射依赖设置（setter dependency injection）这些方式（可供选择），用XML文件将对象连接起来。 IoC是一个简单概念（它允许一个对象在上层接受其他对象的创建），用IoC这种方式让你的对象从创建中释放了出来，降低了偶合度。 <br /><br /><br /><br /><br />这里是一个没有使用IoC的对象创建的例子，它有很高偶合度。 <br /><br /><br /><img src="http://www.onjava.com/onjava/2004/04/07/graphics/nonioc.gif" border="0" /><br /><br /><span style="FONT-STYLE: italic">图 2.没有使用 IoC. A 创建了 B 和 C</span><br /><br />而这里是一个使用IoC的例子，这种方式允许对象在高层可以创建并进入另外一个对象，所以这样可以直接被执行。 <br /><img src="http://www.onjava.com/onjava/2004/04/07/graphics/ioc.gif" border="0" /><br /><br /><span style="FONT-STYLE: italic">图 3. 对象使用了 IoC。 A 包含了接受B,C的 setter方法 , 这同样达到了 由A创建B,C的目的。</span><br /><br />建立我们的业务服务对象（Building Our Business Service Objects） <br /><br /><br />Business Object中的Setter方法接受的是接口，这样我们可以很松散的定义对象实现，然后注入。 在我们的案例中，我们将用一个business service object接收一个DAO,用它来控制domain objects的持久化。 由于在这个例子中使用了Hibernate，我们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了。 <br /><br />在面向接口的编程中，你会明白 “注射依赖”模式是怎样松散耦合你的业务逻辑和持久机制的：）。 <br /><br /><br /><br />下面是一个接口business service object，DAO代码片段： <br /><br /><br /></font>
				</span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">
												<br />public interface IOrderService { <br /><br />  public abstract Order saveNewOrder(Order order) <br /><br />    throws OrderException, <br /><br />           OrderMinimumAmountException; <br /><br />  <br /><br />  public abstract List findOrderByUser( <br /><br />                                     String user) <br /><br />                           throws OrderException; <br /><br />  <br /><br />  public abstract Order findOrderById(int id) <br /><br />                           throws OrderException; <br /><br />  <br /><br />  public abstract void setOrderDAO( <br /><br />                             IOrderDAO orderDAO); <br /><br />} <br /><br /> </td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />注意到这段代码里有一个 setOrderDao（），它就是一个DAO Object设置方法（注射器）。 但这里并没有一个getOrderDao的方法，这不必要，因为你并不会在外部访问这个orderDao。这个DAO Objecte将被调用，和我们的persistence layer 通信。我们将用Spring把DAO Object 和 business service object搭配起来的。因为我们是面向接口编程的，所以并不需要将实现类紧密的耦合在一起。 <br /><br /><br /><br />接下去我们开始我们的DAO的实现类进行编码。 既然Spring已经有对Hibernate的支持，那这个例子就直接继承<a class="postlink" href="http://www.springframework.org/docs/api/org/springframework/orm/hibernate/support/HibernateDaoSupport.html" target="_blank"><font color="#006699">HibernateDaoSupport</font></a>类了，这个类很有用，我们可以参考<a class="postlink" href="http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTemplate.html" target="_blank"><font color="#006699">HibernateTemplate</font></a>（它主要是针对HibernateDaoSupport的一个用法，译注：具体可以查看<a class="postlink" href="http://www.springframework.org/docs/api/index.html" target="_blank"><font color="#006699">Srping 的API</font></a>）。 下面是这个DAO接口代码： <br /><br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">public interface IOrderDAO { <br />  public abstract Order findOrderById( <br />                                    final int id); <br />  <br />  public abstract List findOrdersPlaceByUser( <br />                           final String placedBy); <br />  public abstract Order saveOrder( <br />                               final Order order); <br />}</td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />
						<br />我们仍然要给我们持久层组装很多关联的对象，这里包含了HibernateSessionFactory 和TransactionManager。 Spring 提供了一个 <a class="postlink" href="http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTransactionManager.html" target="_blank"><font color="#006699">HibernateTransactionManager</font></a>，他用线程捆绑了一个Hibernate Session，用它来支持transactions(请查看<a class="postlink" href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html" target="_blank"><font color="#006699">ThreadLocal</font></a>) 。 <br /><br />下面是HibernateSessionFactory 和 HibernateTransactionManager:的配置： <br /><br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">&lt;bean id="mySessionFactory" <br />       class="org.springframework.orm.hibernate. <br />              LocalSessionFactoryBean"&gt; <br />  &lt;property name="mappingResources"&gt; <br />    &lt;list&gt; <br />      &lt;value&gt; <br />        com/meagle/bo/Order.hbm.xml <br />      &lt;/value&gt; <br />      &lt;value&gt; <br />        com/meagle/bo/OrderLineItem.hbm.xml <br />      &lt;/value&gt; <br />    &lt;/list&gt; <br />  &lt;/property&gt; <br />  &lt;property name="hibernateProperties"&gt; <br />    &lt;props&gt; <br />      &lt;prop key="hibernate.dialect"&gt; <br />        net.sf.hibernate.dialect.MySQLDialect <br />      &lt;/prop&gt; <br />      &lt;prop key="hibernate.show_sql"&gt; <br />        false <br />      &lt;/prop&gt; <br />      &lt;prop key="hibernate.proxool.xml"&gt; <br />        C:/MyWebApps/.../WEB-INF/proxool.xml <br />      &lt;/prop&gt; <br />      &lt;prop key="hibernate.proxool.pool_alias"&gt; <br />          spring <br />      &lt;/prop&gt; <br />    &lt;/props&gt; <br />  &lt;/property&gt; <br />&lt;/bean&gt; <br />  <br />&lt;!-- Transaction manager for a single Hibernate <br />SessionFactory (alternative to JTA) --&gt; <br />&lt;bean id="myTransactionManager" <br />         class="org. <br />                springframework. <br />                orm. <br />                hibernate. <br />                HibernateTransactionManager"&gt; <br />  &lt;property name="sessionFactory"&gt; <br />    &lt;ref local="mySessionFactory"/&gt; <br />  &lt;/property&gt; <br />  &lt;/bean&gt;</td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />
						<br />
						<br />可以看出：每个对象都可以在Spring 配置信息中用&lt;bean&gt;标签引用。在这里，mySessionFactory引用了HibernateSessionFactory，而myTransactionManager引用了HibernateTransactionManage。 注意代码中myTransactionManger Bean有个sessionFactory属性。 HibernateTransactionManager有个sessionFactory setter 和 getter方法，这是用来在Spring启动的时候实现“依赖注入” （dependency injection）的。 在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后就被组装了起来了。 这样的搭配让你从 单例（singleton objects）和工厂（factories）中解放了出来，降低了代码的维护代价。 mySessionFactory.的两个属性，分别是用来注入mappingResources 和 hibernatePropertes的。通常，如果你在Spring之外使用Hibernate,这样的设置应该放在hibernate.cfg.xml中的。 不管怎样,Spring提供了一个便捷的方式-----在Spring内部配置中并入了Hibernate的配置。 如果要得到更多的信息，可以查阅Spring API。 <br /><br /><br /><br /><br /><br />既然我们已经组装配置好了Service Beans，就需要把Business Service Object和 DAO也组装起来，并把这些对象配到一个事务管理器（transaction manager）里。 <br /><br /><br /><br />在Spring中的配置信息： <br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">
												<br />&lt;!-- ORDER SERVICE --&gt; <br />&lt;bean id="orderService" <br />  class="org. <br />         springframework. <br />         transaction. <br />         interceptor. <br />         TransactionProxyFactoryBean"&gt; <br />  &lt;property name="transactionManager"&gt; <br />    &lt;ref local="myTransactionManager"/&gt; <br />  &lt;/property&gt; <br />  &lt;property name="target"&gt; <br />    &lt;ref local="orderTarget"/&gt; <br />  &lt;/property&gt; <br />  &lt;property name="transactionAttributes"&gt; <br />    &lt;props&gt; <br />      &lt;prop key="find*"&gt; <br />     PROPAGATION_REQUIRED,readOnly,-OrderException <br />      &lt;/prop&gt; <br />      &lt;prop key="save*"&gt; <br />     PROPAGATION_REQUIRED,-OrderException <br />      &lt;/prop&gt; <br />    &lt;/props&gt; <br />  &lt;/property&gt; <br />&lt;/bean&gt; <br />  <br />&lt;!-- ORDER TARGET PRIMARY BUSINESS OBJECT: <br />Hibernate implementation --&gt; <br />&lt;bean id="orderTarget" <br />         class="com. <br />                meagle. <br />                service. <br />                spring. <br />                OrderServiceSpringImpl"&gt; <br />  &lt;property name="orderDAO"&gt; <br />    &lt;ref local="orderDAO"/&gt; <br />  &lt;/property&gt; <br />&lt;/bean&gt; <br />  <br />&lt;!-- ORDER DAO OBJECT --&gt; <br />&lt;bean id="orderDAO" <br />         class="com. <br />                meagle. <br />                service. <br />                dao. <br />                hibernate. <br />                OrderHibernateDAO"&gt; <br />  &lt;property name="sessionFactory"&gt; <br />    &lt;ref local="mySessionFactory"/&gt; <br />  &lt;/property&gt; <br />&lt;/bean&gt;</td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />
						<br />
						<br />
						<br />图4 是我们对象搭建的一个提纲。 从中可以看出，每个对象都联系着Spring，并且能通过Spring注入到其他对象。把它与Spring的配置文件比较，观察他们之间的关系 <br /><br /><img src="http://www.onjava.com/onjava/2004/04/07/graphics/spring_wiring.gif" border="0" /><br /><br /><span style="FONT-STYLE: italic">图 4. Spring就是这样基于配置文件，将各个Bean搭建在一起。</span><br /><br />这个例子使用一个TransactionProxyFactoryBean，它定义了一个setTransactionManager()。 这对象很有用，他能很方便的处理你申明的事物还有Service Object。 你可以通过transactionAttributes属性来定义怎样处理。 想知道更多还是参考TransactionAttributeEditor吧。 <br /><br />TransactionProxyFactoryBean 还有个setter. 这会被我们 Business service object（orderTarget）引用， orderTarget定义了 业务服务层，并且它还有个属性，由setOrderDAO()引用。这个属性 <br /><br /><br /><br />Spring 和Bean 的还有一点要注意的： bean可以以用两种方式创造。 这些都在单例模式（Sington）和原型模式（propotype）中定义了。 默认的方式是singleton,这意味着共享的实例将被束缚。 而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得到他们自己Bean的Copy时，你应该仅使用prototype模式。（更多的请参考设计模式中的单例模式和原形模式） <br /><br /><span style="FONT-WEIGHT: bold">提供一个服务定位器（Providing a Service Locator）</span><br />既然我们已经将我们的Serices和DAO搭配起来了。我们需要把我们的Service显示到其他层。 这个通常是在Struts或者Swing这层里编码。一个简单方法就是用 服务定位器返回给Spring context 。当然，可以通过直接调用Spring中的Bean来做。 <br /><br />下面是一个Struts Actin 中的服务定位器的一个例子。 <br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">
												<br />public abstract class BaseAction extends Action { <br />  <br />  private IOrderService orderService; <br />  <br />  public void setServlet(ActionServlet <br />                                 actionServlet) { <br />    super.setServlet(actionServlet); <br />    ServletContext servletContext = <br />               actionServlet.getServletContext(); <br />  <br />    WebApplicationContext wac = <br />      WebApplicationContextUtils. <br />         getRequiredWebApplicationContext( <br />                                 servletContext); <br />  <br />      this.orderService = (IOrderService) <br />                     wac.getBean("orderService"); <br />  } <br />  <br />  protected IOrderService getOrderService() { <br />    return orderService; <br />  } <br />} <br /> </td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />
						<span style="FONT-WEIGHT: bold">UI 层配置 （UI Layer Configuration）</span>
						<br />
						<br />这个例子里UI层 使用了Struts framework. 这里我们要讲述一下在给程序分层的时候， 哪些是和Struts部分的。我们就从一个Struts-config.xml文件中的Action的配置信息开始吧。 <br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">
												<br />struts-config.xml file. <br /><br />&lt;action path="/SaveNewOrder" <br />    type="com.meagle.action.SaveOrderAction" <br />    name="OrderForm" <br />    scope="request" <br />    validate="true" <br />    input="/NewOrder.jsp"&gt; <br />  &lt;display-name&gt;Save New Order&lt;/display-name&gt; <br />  &lt;exception key="error.order.save" <br />    path="/NewOrder.jsp" <br />    scope="request" <br />    type="com.meagle.exception.OrderException"/&gt; <br />  &lt;exception key="error.order.not.enough.money" <br />    path="/NewOrder.jsp" <br />    scope="request" <br />    type="com. <br />          meagle. <br />          exception. <br />          OrderMinimumAmountException"/&gt; <br />  &lt;forward name="success" path="/ViewOrder.jsp"/&gt; <br />  &lt;forward name="failure" path="/NewOrder.jsp"/&gt; <br />&lt;/action&gt;</td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />SaveNewOrder 这个Action是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察这个Action中exception配置，这些Exceptions也在Spring 配置文件(applicationContext-hibernate.xml)中配置了（就在 business service object 的transactionAttributes属性里）。 当异常在业务层被被抛出时，我们可以控制他们，并适当的显示给UI层。 <br /><br />第一个异常，OrderException,在持久层保存order对象失败的时候被触发。这将导致事物回滚并且通过BO把异常回传到Struts这一层。 <br /><br />第二个异常，OrderMinimumAmountException也同第一个一样。 <br /><br /><br /><br /><br /><br />搭配整和的最后一步 通过是让你显示层和业务层相结合。这个已经被服务定位器（service locator）实现了（前面讨论过了）， 这里服务层作为一个接口提供给我们的业务逻辑和持久层。 <br /><br /><br /><br />SaveNewOrder Action 在Struts中用一个服务定位器（service locator）来调用执行业务方法的。 方法代码如下： <br /><br /><br /><br /></span>
				<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
						<tbody>
								<tr>
										<td>
												<span class="genmed">
														<b>
																<font size="2">代码:</font>
														</b>
												</span>
										</td>
								</tr>
								<tr>
										<td class="code">public ActionForward execute( <br /><br />  ActionMapping mapping, <br /><br />  ActionForm form, <br /><br />  javax.servlet.http.HttpServletRequest request, <br /><br />  javax.servlet.http.HttpServletResponse response) <br /><br />  throws java.lang.Exception { <br /><br />  <br /><br />  OrderForm oForm = (OrderForm) form; <br /><br />  <br /><br />  // Use the form to build an Order object that <br /><br />  // can be saved in the persistence layer. <br /><br />  // See the full source code in the sample app. <br /><br />  <br /><br />  // Obtain the wired business service object <br /><br />  // from the service locator configuration <br /><br />  // in BaseAction. <br /><br />  // Delegate the save to the service layer and <br /><br />  // further upstream to save the Order object. <br /><br />  getOrderService().saveNewOrder(order); <br /><br />  <br /><br />  oForm.setOrder(order); <br /><br />  <br /><br />  ActionMessages messages = new ActionMessages(); <br /><br />  messages.add( <br /><br />      ActionMessages.GLOBAL_MESSAGE, <br /><br />            new ActionMessage( <br /><br />      "message.order.saved.successfully")); <br /><br />  <br /><br />  saveMessages(request, messages); <br /><br />  <br /><br />  return mapping.findForward("success"); <br /><br />}</td>
								</tr>
						</tbody>
				</table>
				<span class="postbody">
						<br />
						<br />总结 <br /><br />这篇文章在技术和构架方面掩盖了很多低层的基础信息， 文章的主要的意图在于让你意识到如何给你应用程序分层。 分层可以“解耦”你的代码——允许新的组件被添加进来，而且让你的代码易于维护。 这里用到的技术只是专注于把“解偶”做好。 不管怎样，使用这样的构架可以让你用其他技术代替现在的层。 例如，你可能不使用Hibernate实现持久化。既然你在DAO中面向接口的编程的，所以你完全可以用iBATIS来代替。或者，你也可能想用Struts外的其他的技术或者框架替换现在的UI层（转换久层，实现层并不应该直接影响到你的业务逻辑和业务服务层）。 用适当的框架搭建你的Web应用，其实也不是一件烦琐的工作，更主要的是它“解耦”了你程序中的各个层。 <br /><br /><br /><br /><br /><br />后记： <br /><br />看完这篇文章后，只是觉得很喜欢，于是就翻译了，当然同时也准备着挨大家扔来的鸡蛋：）。 <br /><br />这篇文章里并没有太多的技术细节，和详细的步骤。如果你从未使用过这些框架而在运行实例程序遇上困难的话，可以到CSDN论坛Java Open Source版发贴，我一定会详细解答的（啊哦，这不算做广告吧？）， <br /><br />文章是从一个构架的角度讲述了如何搭配现有的开源框架进行分层， 有太多的术语我都不知道怎么表达，而且可能有很多语句存在错误。如果影响了你的阅读，请你直接点原文地址，我同时也象你说声抱歉。 <br /><br /><br /><br />作者简介：Mark Eagle 高级软件工程师，亚特兰大。 <br />翻 译：Totodo,软件工程师 </span>
		</span>
		<br />
		<div style="FONT-SIZE: 14px; LINE-HEIGHT: 25px">
				<strong>作者Blog：</strong>
				<a id="ArticleContent1_ArticleContent1_AuthorBlogLink" href="http://blog.csdn.net/chinaewolf/" target="_blank">http://blog.csdn.net/chinaewolf/</a>
		</div>
<img src ="http://www.blogjava.net/LeungXin/aggbug/74821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/LeungXin/" target="_blank">梁昕</a> 2006-10-12 17:08 <a href="http://www.blogjava.net/LeungXin/articles/74821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>