2023年全國(guó)碩士研究生考試考研英語(yǔ)一試題真題(含答案詳解+作文范文)_第1頁(yè)
已閱讀1頁(yè),還剩119頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、<p>  2  Jive與設(shè)計(jì)模式</p><p>  Jive論壇系統(tǒng)使用大量設(shè)計(jì)模式巧妙地實(shí)現(xiàn)了一系列功能。因?yàn)樵O(shè)計(jì)模式的通用性和可理解性,將幫助更多人很快地理解 Jive論壇源碼,從而可以依據(jù)一種“協(xié)定”來(lái)動(dòng)態(tài)地?cái)U(kuò)展它。那么使用設(shè)計(jì)模式還有哪些好處?</p><p><b>  2.1  設(shè)計(jì)模式</b></p>&

2、lt;p>  設(shè)計(jì)模式是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無(wú)疑問(wèn),設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的。設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石。</p><p>  GOF(設(shè)計(jì)模式作者簡(jiǎn)稱)《設(shè)計(jì)模式》這本書第一次將設(shè)計(jì)模式提升到理論高度,并將之規(guī)范化,該書提出了23種基本設(shè)計(jì)模式。自此,

3、在可復(fù)用面向?qū)ο筌浖陌l(fā)展過(guò)程中,新的大量的設(shè)計(jì)模式不斷出現(xiàn)。</p><p>  很多人都知道Java是完全面向?qū)ο蟮脑O(shè)計(jì)和編程語(yǔ)言,但是由于接受教育以及經(jīng)驗(yàn)的原因,大多數(shù)程序員或設(shè)計(jì)人員都是從傳統(tǒng)的過(guò)程語(yǔ)言轉(zhuǎn)變而來(lái),因此在思維習(xí)慣上要完全轉(zhuǎn)變?yōu)槊嫦驅(qū)ο蟮脑O(shè)計(jì)和開發(fā)方式是困難的,而學(xué)習(xí)設(shè)計(jì)模式可以更好地幫助和堅(jiān)固這種轉(zhuǎn)變。</p><p>  凡是學(xué)習(xí)完成設(shè)計(jì)模式的人都有一種類似重生的感

4、覺,這種重生可以從很多方面去解釋。換一種新的角度來(lái)看待和解決問(wèn)題應(yīng)該是一種比較貼切的解釋,而這種新的思維角度培養(yǎng)屬于基礎(chǔ)培訓(xùn),因此,設(shè)計(jì)模式是學(xué)習(xí)Java的必讀基礎(chǔ)課程之一。</p><p>  由于設(shè)計(jì)模式概念比較抽象,對(duì)于初學(xué)者學(xué)習(xí)有一定的難度,因此結(jié)合Jive論壇系統(tǒng)學(xué)習(xí)設(shè)計(jì)模式將是一種很好的選擇。</p><p>  掌握了設(shè)計(jì)模式,將會(huì)幫助程序員或設(shè)計(jì)人員以更加可重用性、可伸縮性

5、的眼光來(lái)開發(fā)應(yīng)用系統(tǒng),甚至開發(fā)通用的框架系統(tǒng)。框架系統(tǒng)是構(gòu)成一類特定軟件可復(fù)用設(shè)計(jì)的一組相互協(xié)作的類,主要是對(duì)應(yīng)用系統(tǒng)中反復(fù)重用部分的提煉,類似一種模板,這是一種結(jié)構(gòu)性的模板。</p><p>  框架通常定義了應(yīng)用體系的整體結(jié)構(gòu)、類和對(duì)象的關(guān)系等設(shè)計(jì)參數(shù),以便于具體應(yīng)用實(shí)現(xiàn)者能集中精力于應(yīng)用本身的特定細(xì)節(jié)??蚣軓?qiáng)調(diào)設(shè)計(jì)復(fù)用,而設(shè)計(jì)模式最小的可重用單位,因此框架不可避免地會(huì)反復(fù)使用到設(shè)計(jì)模式。關(guān)于通用框架系統(tǒng)的設(shè)

6、計(jì)開發(fā)將在以后章節(jié)中討論。</p><p>  其實(shí)Jive論壇本身也形成了一個(gè)基于Web結(jié)構(gòu)的通用框架系統(tǒng),因?yàn)樗芏嘣O(shè)計(jì)思想是可以重用的,例如設(shè)定一個(gè)總體入口,通過(guò)入口檢查用戶的訪問(wèn)控制權(quán)限,當(dāng)然還有其他各方面的功能實(shí)現(xiàn)方式都是值得在其他系統(tǒng)中借鑒的,也正因?yàn)樗阅J降男问奖憩F(xiàn)出來(lái),這種可重用性和可借鑒性就更強(qiáng)。</p><p>  2.2  ForumFactory與工廠模

7、式</p><p>  工廠模式是GOF設(shè)計(jì)模式的主要常用模式,它主要是為創(chuàng)建對(duì)象提供了一種接口,工廠模式主要是封裝了創(chuàng)建對(duì)象的細(xì)節(jié)過(guò)程,從而使得外界調(diào)用一個(gè)對(duì)象時(shí),根本無(wú)需關(guān)心這個(gè)對(duì)象是如何產(chǎn)生的。</p><p>  在GOF設(shè)計(jì)模式中,工廠模式分為工廠方法模式和抽象工廠模式。兩者主要區(qū)別是,工廠方法是創(chuàng)建一種產(chǎn)品接口下的產(chǎn)品對(duì)象,而抽象工廠模式是創(chuàng)建多種產(chǎn)品接口下的產(chǎn)品對(duì)象,非常類似

8、Builder生成器模式。在平時(shí)實(shí)踐中,使用較多的基本是工廠方法模式。</p><p>  以類SampleOne為例,要?jiǎng)?chuàng)建SampleOne的對(duì)象實(shí)例:</p><p>  SampleOne sampleOne = new SampleOne();</p><p>  如果Sample類有幾個(gè)相近的類:SampleTwo或SampleThree,那么創(chuàng)建它們的

9、實(shí)例分別是:</p><p>  SampleTwo sampleTwo = new SampleTwo();</p><p>  SampleThree sampleThree = new SampleThree();</p><p>  其實(shí)這3個(gè)類都有一些共同的特征,如網(wǎng)上商店中銷售書籍、玩具或者化妝品。雖然它們是不同的具體產(chǎn)品,但是它們有一個(gè)共同特征,可以抽

10、象為“商品”。日常生活中很多東西都可以這樣高度抽象成一種接口形式。上面這3個(gè)類如果可以抽象為一個(gè)統(tǒng)一接口SampleIF,那么上面語(yǔ)句就可以成為:</p><p>  SampleIF sampleOne = new SampleOne();</p><p>  SampleIF sampleTwo = new SampleTwo();</p><p>  Samp

11、leIF sampleThree = new SampleThree();</p><p>  在實(shí)際情況中,有時(shí)并不需要同時(shí)生成3種對(duì)象,而是根據(jù)情況在3者之中選一個(gè)。在這種情況下,需要使用工廠方法來(lái)完成了,創(chuàng)建一個(gè)叫SampleFactory的抽象類:</p><p>  public class SampleFactory{</p><p>  public

12、abstract SampleIF creator();</p><p><b>  }</b></p><p>  在這個(gè)抽象工廠類中有一個(gè)抽象方法creator,但是沒有具體實(shí)現(xiàn),而是延遲到它的子類中實(shí)現(xiàn),創(chuàng)建子類SampleFactoryImp:</p><p>  public class SampleFactoryImp extend

13、s SampleFactory{</p><p>  public SampleIF creator(){</p><p>  //根據(jù)其他因素綜合判斷返回具體產(chǎn)品</p><p>  //假設(shè)應(yīng)該返回SampleOne對(duì)象</p><p>  return new SampleOne();</p><p><b

14、>  }</b></p><p><b>  }</b></p><p>  在SampleFactoryImp中根據(jù)具體情況來(lái)選擇返回SampleOne、SampleTwo或SampleThree。所謂具體情況有很多種:上下文其他過(guò)程計(jì)算結(jié)果;直接根據(jù)配置文件中配置。</p><p>  上述工廠方法模式中涉及到一個(gè)抽象產(chǎn)品

15、接口Sample,如果還有其他完全不同的產(chǎn)品接口,如Product等,一個(gè)子類SampleFactoryImp只能實(shí)現(xiàn)一套系列產(chǎn)品方案的生產(chǎn),如果還需要另外一套系統(tǒng)產(chǎn)品方案,就可能需要另外一個(gè)子類SampleFactoryImpTwo來(lái)實(shí)現(xiàn)。這樣,多個(gè)產(chǎn)品系列、多個(gè)工廠方法就形成了抽象工廠模式。</p><p>  前面已經(jīng)討論在Jive中設(shè)置了論壇統(tǒng)一入口,這個(gè)統(tǒng)一入口就是ForumFactory,以下是For

16、umFactory的主要代碼:</p><p>  public abstract class ForumFactory {</p><p>  private static Object initLock = new Object();</p><p>  private static String className = " com.Yasna.for

17、um.database.DbForumFactory";</p><p>  private static ForumFactory factory = null; </p><p>  public static ForumFactory getInstance(Authorization authorization) {</p><p>  if (a

18、uthorization == null) {</p><p>  return null;</p><p><b>  }</b></p><p>  //以下使用了Singleton 單態(tài)模式,將在2.3節(jié)討論</p><p>  if (factory == null) {</p><p>

19、  synchronized(initLock) {</p><p>  if (factory == null) {</p><p>  ... //從配置文件中獲得當(dāng)前className</p><p><b>  try {</b></p><p><b>  //動(dòng)態(tài)裝載類</b></

20、p><p>  Class c = Class.forName(className);</p><p>  factory = (ForumFactory)c.newInstance();</p><p><b>  }</b></p><p>  catch (Exception e) {</p><p

21、>  return null;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  //返回 pr

22、oxy.用來(lái)限制授權(quán)對(duì)forum的訪問(wèn)</p><p>  return new ForumFactoryProxy(authorization, factory,factory.getPermissions(authorization));</p><p><b>  }</b></p><p>  //創(chuàng)鍵產(chǎn)品接口Forum的具體對(duì)象實(shí)例&

23、lt;/p><p>  public abstract Forum createForum(String name, String description)</p><p>  throws UnauthorizedException, ForumAlreadyExistsException;</p><p>  //創(chuàng)鍵產(chǎn)品接口ForumThread的具體對(duì)象實(shí)例&l

24、t;/p><p>  public abstract ForumThread createThread(ForumMessage rootMessage) </p><p>  throws UnauthorizedException;</p><p>  //創(chuàng)鍵產(chǎn)品接口ForumMessage的具體對(duì)象實(shí)例</p><p>  public

25、abstract ForumMessage createMessage();</p><p><b>  ....</b></p><p><b>  }</b></p><p>  ForumFactory中提供了很多抽象方法如createForum、createThread和createMessage()等,它們是創(chuàng)建

26、各自產(chǎn)品接口下的具體對(duì)象,這3個(gè)接口就是前面分析的基本業(yè)務(wù)對(duì)象Forum、ForumThread和ForumMessage,這些創(chuàng)建方法在ForumFactory中卻不立即執(zhí)行,而是推遲到ForumFactory子類中實(shí)現(xiàn)。</p><p>  ForumFactory的子類實(shí)現(xiàn)是com.Yasna.forum.database.DbForumFactory,這是一種數(shù)據(jù)庫(kù)實(shí)現(xiàn)方式。即在DbForumFactor

27、y中分別實(shí)現(xiàn)了在數(shù)據(jù)庫(kù)中createForum、createThread和createMessage()等3種方法,當(dāng)然也提供了動(dòng)態(tài)擴(kuò)展到另外一套系列產(chǎn)品的生產(chǎn)方案的可能。如果使用XML來(lái)實(shí)現(xiàn),那么可以編制一個(gè)XmlForumFactory的具體工廠子類來(lái)分別實(shí)現(xiàn)3種創(chuàng)建方法。</p><p>  因此,Jive論壇在統(tǒng)一入口處使用了抽象工廠模式來(lái)動(dòng)態(tài)地創(chuàng)建論壇中所需要的各種產(chǎn)品,如圖3-4所示。</p&g

28、t;<p>  圖3-4  ForumFactory抽象工廠模式圖</p><p>  圖3-4中,XmlForumFactory和DbForumFactory作為抽象工廠ForumFactory的兩個(gè)具體實(shí)現(xiàn),而Forum、ForumThread和ForumMessage分別作為3個(gè)系列抽象產(chǎn)品接口,依靠不同的工廠實(shí)現(xiàn)方式,會(huì)產(chǎn)生不同的產(chǎn)品對(duì)象。</p><p>

29、  從抽象工廠模式去理解Jive論壇統(tǒng)一入口處,可以一步到位掌握了幾個(gè)類之間的大概關(guān)系。因?yàn)槭褂昧顺橄蠊S模式這種通用的設(shè)計(jì)模式,可以方便源碼閱讀者快速地掌握整個(gè)系統(tǒng)的結(jié)構(gòu)和來(lái)龍去脈,圖3-4這張圖已經(jīng)初步展示了Jive的主要框架結(jié)構(gòu)。</p><p>  細(xì)心的讀者也許會(huì)發(fā)現(xiàn),在上面ForumFactory有一個(gè)getInstance比較令人費(fèi)解,這將在2.3節(jié)進(jìn)行討論。</p><p>

30、;  2.3  統(tǒng)一入口與單態(tài)模式</p><p>  在上面ForumFactory的getInstance方法使用單態(tài)(SingleTon)模式。單態(tài)模式是保證一個(gè)類有且僅有一個(gè)對(duì)象實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。</p><p>  前面曾提到ForumFactory是Jive提供客戶端訪問(wèn)數(shù)據(jù)庫(kù)系統(tǒng)的統(tǒng)一入口。為了保證所有的客戶端請(qǐng)求都要經(jīng)過(guò)這個(gè)ForumFactor

31、y,如果不使用單態(tài)模式,客戶端下列調(diào)用語(yǔ)句表示生成了ForumFactory實(shí)例:</p><p>  ForumFactory factory = new DbForumFactory();</p><p>  客戶端每發(fā)生一次請(qǐng)求都調(diào)用這條語(yǔ)句,這就會(huì)發(fā)生每次都生成不同factory對(duì)象實(shí)例,這顯然不符合設(shè)計(jì)要求,因此必須使用單態(tài)模式。</p><p>  一般

32、在Java實(shí)現(xiàn)單態(tài)模式有幾種選擇,最常用而且安全的用法如下:</p><p>  public class Singleton { </p><p>  private Singleton(){}</p><p>  //在自己內(nèi)部定義自己一個(gè)實(shí)例,是不是很奇怪</p><p>  //注意這是private,只供內(nèi)部調(diào)用</p>

33、<p>  private static Singleton instance = new Singleton(); </p><p>  //這里提供了一個(gè)供外部訪問(wèn)本class的靜態(tài)方法,可以直接訪問(wèn)</p><p>  public static Singleton getInstance() { </p><p>  return instan

34、ce; </p><p><b>  } </b></p><p><b>  }</b></p><p>  單態(tài)模式一共使用了兩條語(yǔ)句實(shí)現(xiàn):第一條直接生成自己的對(duì)象,第二條提供一個(gè)方法供外部調(diào)用這個(gè)對(duì)象,同時(shí)最好將構(gòu)造函數(shù)設(shè)置為private,以防止其他程序員直接使用new Singleton生成實(shí)例。</p&g

35、t;<p>  還有一種Java單態(tài)模式實(shí)現(xiàn):</p><p>  public class Singleton { </p><p>  private Singleton(){}</p><p>  private static Singleton instance = null; </p><p>  public sta

36、tic synchronized Singleton getInstance() { </p><p>  if (instance==null)</p><p>  instance=new Singleton() </p><p>  return instance; </p><p><b>  }</b><

37、/p><p><b> ?。?lt;/b></p><p>  在上面代碼中,使用了判斷語(yǔ)句。如果instance為空,再進(jìn)行實(shí)例化,這成為lazy initialization。注意getInstance()方法的synchronized,這個(gè)synchronized很重要。如果沒有synchronized,那么使用getInstance()在第一次被訪問(wèn)時(shí)有可能得到多個(gè)Si

38、ngleton實(shí)例。</p><p>  關(guān)于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的討論,有興趣者可以進(jìn)一步研究。一般認(rèn)為第一種形式要更加安全些;但是后者可以用在類初始化時(shí)需要參數(shù)輸入的情況下。</p><p>  在Jive的ForumFactory中采取了后者lazy initialization形

39、式,這是為了能夠動(dòng)態(tài)配置指定ForumFactory的具體子類。在getInstance中,從配置文件中獲得當(dāng)前工廠的具體實(shí)現(xiàn),如果需要啟動(dòng)XmlForumFactory,就不必修改ForumFactory代碼,直接在配置文件中指定className的名字為XmlForumFactory。這樣通過(guò)下列動(dòng)態(tài)裝載機(jī)制生成ForumFactory具體對(duì)象:</p><p>  Class c = Class.forNa

40、me(className);</p><p>  factory = (ForumFactory)c.newInstance();</p><p>  這是利用Java的反射機(jī)制,可以通過(guò)動(dòng)態(tài)指定className的數(shù)值而達(dá)到生成對(duì)象的方式。</p><p>  使用單態(tài)模式的目標(biāo)是為了控制對(duì)象的創(chuàng)建,單態(tài)模式經(jīng)常使用在控制資源的訪問(wèn)上。例如數(shù)據(jù)庫(kù)連接或Socket

41、連接等。單態(tài)模式可以控制在某個(gè)時(shí)刻只有一個(gè)線程訪問(wèn)資源。由于Java中沒有全局變量的概念,因此使用單態(tài)模式有時(shí)可以起到這種作用,當(dāng)然需要注意是在一個(gè)JVM中。</p><p>  2.4  訪問(wèn)控制與代理模式</p><p>  仔細(xì)研究會(huì)發(fā)現(xiàn),在ForumFactory的getInstance方法中最后的返回值有些奇怪。按照單態(tài)模式的概念應(yīng)該直接返回factory這個(gè)對(duì)象實(shí)例,

42、但是卻返回了ForumFactoryProxy的一個(gè)實(shí)例,這實(shí)際上改變了單態(tài)模式的初衷。這樣客戶端每次通過(guò)調(diào)用ForumFactory的getInstance返回的就不是ForumFactory的惟一實(shí)例,而是新的對(duì)象。之所以這樣做是為了訪問(wèn)權(quán)限的控制,姑且不論這樣做的優(yōu)劣,先看看什么是代理模式。</p><p>  代理模式是屬于設(shè)計(jì)模式結(jié)構(gòu)型模式中一種,它是實(shí)際訪問(wèn)對(duì)象的代理對(duì)象,或者影子對(duì)象,主要達(dá)到控制實(shí)

43、際對(duì)象的訪問(wèn)。這種控制的目的很多,例如提高性能等。即遠(yuǎn)程代理模式,這種模式將在以后章節(jié)討論。</p><p>  其中一個(gè)主要的控制目的是控制客戶端對(duì)實(shí)際對(duì)象的訪問(wèn)權(quán)限。在Jive系統(tǒng)中,因?yàn)橛薪巧珯?quán)限的分別,對(duì)于Forum、ForumThread和FroumMessage的訪問(wèn)操作必須經(jīng)過(guò)權(quán)限機(jī)制驗(yàn)證后才能進(jìn)行。</p><p>  以ForumFactoryProxy中的createF

44、orum方法為例,其實(shí)ForumFactoryProxy也是FroumFactory的一種工廠實(shí)現(xiàn),它的createForum具體實(shí)現(xiàn)如下:</p><p>  public Forum createForum(String name, String description)</p><p>  throws UnauthorizedException, ForumAlreadyExist

45、sException</p><p><b>  {</b></p><p>  if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {</p><p>  Forum newForum = factory.createForum(name, description);</p>

46、<p>  return new ForumProxy(newForum, authorization, permissions);</p><p><b>  }</b></p><p><b>  else {</b></p><p>  throw new UnauthorizedException();&

47、lt;/p><p><b>  }</b></p><p><b>  }</b></p><p>  在這個(gè)方法中進(jìn)行了權(quán)限驗(yàn)證,判斷是否屬于系統(tǒng)管理員。如果是,將直接從DbForumFactory對(duì)象factory的方法createForum中獲得一個(gè)新的Forum對(duì)象,然后再返回Forum的子類代理對(duì)象ForumProx

48、y。因?yàn)樵贔orum中也還有很多屬性和操作方法,這些也需要進(jìn)行權(quán)限驗(yàn)證。ForumProxy和ForumFactoryProxy起到類似的作用。</p><p>  Jive中有下列幾個(gè)代理類:</p><p>  ?          ForumFactoryProxy:客戶端和DbForumFac

49、tory之間的代理??蛻舳嗽L問(wèn)DbForumFactory的任何方法都要先經(jīng)過(guò)ForumFactoryProxy相應(yīng)方法代理一次。以下意思相同。</p><p>  ?          ForumProxy:客戶端和DbForum之間的代理,研究Forum對(duì)象的每個(gè)方法,必須先看ForumProxy對(duì)象的方法。</p

50、><p>  ?          ForumMessageProxy:客戶端和DbForumMessage之間的代理。</p><p>  ?          ForumThreadProxy:客戶端和DbFor

51、umThread之間的代理。</p><p>  User和Group也有相應(yīng)的代理類。</p><p>  由以上分析看出,每個(gè)數(shù)據(jù)對(duì)象都有一個(gè)代理。如果系統(tǒng)中數(shù)據(jù)對(duì)象非常多,依據(jù)這種一對(duì)一的代理關(guān)系,會(huì)有很多代理類,將使系統(tǒng)變得不是非常干凈,因此可以使用動(dòng)態(tài)代理來(lái)代替這所有的代理類,具體實(shí)現(xiàn)將在以后章節(jié)討論。</p><p>  2.5  批量分頁(yè)查詢

52、與迭代模式</p><p>  迭代(Iterator)模式是提供一種順序訪問(wèn)某個(gè)集合各個(gè)元素的方法,確保不暴露該集合的內(nèi)部表現(xiàn)。迭代模式應(yīng)用于對(duì)大量數(shù)據(jù)的訪問(wèn),Java Collection API中Iterator就是迭代模式的一種實(shí)現(xiàn)。</p><p>  在前面章節(jié)已經(jīng)討論過(guò),用戶查詢大量數(shù)據(jù),從數(shù)據(jù)庫(kù)不應(yīng)該直接返回ResultSet,應(yīng)該是Collection。但是有一個(gè)問(wèn)題,如

53、果這個(gè)數(shù)據(jù)很大,需要分頁(yè)面顯示。如果一下子將所有頁(yè)面要顯示的數(shù)據(jù)都查詢出來(lái)放在Collection,會(huì)影響性能。而使用迭代模式則不必將全部集合都展現(xiàn)出來(lái),只有遍歷到某個(gè)元素時(shí)才會(huì)查詢數(shù)據(jù)庫(kù)獲得這個(gè)元素的數(shù)據(jù)。</p><p>  以論壇中顯示帖子主題為例,在一個(gè)頁(yè)面中不可能顯示所有主題,只有分頁(yè)面顯示,如圖3-5所示。</p><p>  圖3-5中一共分15頁(yè)來(lái)顯示所有論壇帖子,可以從顯

54、示Forum.jsp中發(fā)現(xiàn)下列語(yǔ)句可以完成上述結(jié)果:</p><p>  ResultFilter filter = new ResultFilter();  //設(shè)置結(jié)果過(guò)濾器</p><p>  filter.setStartIndex(start);          

55、60;  //設(shè)置開始點(diǎn)</p><p>  filter.setNumResults(range);          //設(shè)置范圍</p><p>  ForumThreadIterator threads = forum.threads(filter);  //獲得迭代器&l

56、t;/p><p>  while(threads.hasNext){</p><p>  //逐個(gè)顯示threads中帖子主題,輸出圖3-5中的每一行 </p><p><b>  }</b></p><p>  圖3-5  分頁(yè)顯示所有帖子</p><p>  上述代碼中主要是從Forum

57、的threads方法獲得迭代器ForumThreadIterator的實(shí)例,依據(jù)前面代理模式中分析、研究Forum對(duì)象的方法,首先是看ForumProxy中對(duì)應(yīng)方法,然后再看DbForum中對(duì)應(yīng)方法的具體實(shí)現(xiàn)。在ForumProxy中,threads方法如下:</p><p>  public ForumThreadIterator threads(ResultFilter resultFilter) {<

58、/p><p>  ForumThreadIterator iterator = forum.threads(resultFilter);</p><p>  return new ForumThreadIteratorProxy(iterator, authorization, permissions);</p><p><b>  }</b>&l

59、t;/p><p>  首先是調(diào)用了DbForum中具體的threads方法,再追蹤到DbForum中看看,它的threads方法代碼如下:</p><p>  public ForumThreadIterator threads(ResultFilter resultFilter) {</p><p>  //按resultFilter設(shè)置范圍要求獲得SQL查詢語(yǔ)句&l

60、t;/p><p>  String query = getThreadListSQL(resultFilter, false);  </p><p>  //獲得resultFilter設(shè)置范圍內(nèi)的所有ThreadID集合</p><p>  long [] threadBlock = getThreadBlock(query.toString(), resu

61、ltFilter.getStartIndex());</p><p>  //以下是計(jì)算查詢區(qū)域的開始點(diǎn)和終點(diǎn)</p><p>  int startIndex = resultFilter.getStartIndex();</p><p>  int endIndex;</p><p>  // If number of results i

62、s set to inifinite, set endIndex to the total</p><p>  // number of threads in the forum.</p><p>  if (resultFilter.getNumResults() == ResultFilter.NULL_INT) {</p><p>  endIndex = (

63、int)getThreadCount(resultFilter);</p><p><b>  }else {</b></p><p>  endIndex = resultFilter.getNumResults() + startIndex;</p><p><b>  }</b></p><p&g

64、t;  return new ForumThreadBlockIterator(threadBlock, query.toString(),</p><p>  startIndex, endIndex, this.id, factory);</p><p><b>  }</b></p><p>  ResultFilter是一個(gè)查詢結(jié)果類,

65、可以對(duì)論壇主題Thread和帖子內(nèi)容Message進(jìn)行過(guò)濾或排序,這樣就可以根據(jù)用戶要求定制特殊的查詢范圍。如查詢某個(gè)用戶去年在這個(gè)論壇發(fā)表的所有帖子,那只要?jiǎng)?chuàng)建一個(gè)ResultFilter對(duì)象就可以代表這個(gè)查詢要求。</p><p>  在上面threads方法代碼中,第一步是先定制出相應(yīng)的動(dòng)態(tài)SQL查詢語(yǔ)句,然后使用這個(gè)查詢語(yǔ)句查詢數(shù)據(jù)庫(kù),獲得查詢范圍內(nèi)所有的ForumThread的ID集合,然后在這個(gè)ID集

66、合中獲得當(dāng)前頁(yè)面的ID子集合,這是非常關(guān)鍵的一步。</p><p>  在這關(guān)鍵的一步中,有兩個(gè)重要的方法getThreadListSQL和getThreadBlock:</p><p>  ?          GetThreadListSQL:獲得SQL查詢語(yǔ)句query的值,這個(gè)方法Jive實(shí)現(xiàn)

67、起來(lái)顯得非常地瑣碎。</p><p>  ?          GetThreadBlock:獲得當(dāng)前頁(yè)面的ID子集合,那么如何確定ID子集合的開始位置呢?查看getThreadBlock方法代碼,可以發(fā)現(xiàn),它是使用最普遍的ResultSet next()方法來(lái)逐個(gè)跳躍到開始位置。</p><p> 

68、 上面代碼的Threads方法中最后返回的是ForumThreadBlockIterator,它是抽象類ForumThreadIterator的子類,而ForumThreadIterator繼承了Collection的Iterator,以此聲明自己是一個(gè)迭代器,F(xiàn)orumMessageBlockIterator實(shí)現(xiàn)的具體方法如下:</p><p>  public boolean hasNext(); 

69、    //判斷是否有下一個(gè)元素</p><p>  public boolean hasPrevious()  //判斷是否有前一個(gè)元素</p><p>  public Object next() throws java.util.NoSuchElementException  //獲得下一個(gè)元素實(shí)例</p><p&

70、gt;  ForumThreadBlockIterator中的Block是“頁(yè)”的意思,它的一個(gè)主要類變量threadBlock包含的是一個(gè)頁(yè)面中所有ForumThread的ID,next()方法實(shí)際是對(duì)threadBlock中ForumThread進(jìn)行遍歷,如果這個(gè)頁(yè)面全部遍歷完成,將再獲取下一頁(yè)(Block)數(shù)據(jù)。</p><p>  在ForumThreadBlockIterator重要方法getEleme

71、nt中實(shí)現(xiàn)了兩個(gè)功能:</p><p>  ?          如果當(dāng)前遍歷指針超過(guò)當(dāng)前頁(yè)面,將使用getThreadBlock獲得下一個(gè)頁(yè)面的ID子集合;</p><p>  ?          如果當(dāng)前遍

72、歷指針在當(dāng)前頁(yè)面之內(nèi),根據(jù)ID獲得完整的數(shù)據(jù)對(duì)象,實(shí)現(xiàn)輸出;</p><p>  ForumThreadBlockIterator的getElement方法代碼如下:</p><p>  private Object getElement(int index) {</p><p>  if (index < 0) {   

73、0;    return null;        }</p><p>  // 檢查所要獲得的 element 是否在本查詢范圍內(nèi)(當(dāng)前頁(yè)面內(nèi))</p><p>  if (index < blockStart || </p><p>  index >

74、= blockStart + DbForum.THREAD_BLOCK_SIZE) {   </p><p><b>  try {</b></p><p>  //從緩沖中獲得Forum實(shí)例</p><p>  DbForum forum = factory.cacheManager.forumCache.get(foru

75、mID);</p><p>  //獲得下一頁(yè)的內(nèi)容</p><p>  this.threadBlock = forum.getThreadBlock(query, index);</p><p>  this.blockID = index / DbForum.THREAD_BLOCK_SIZE;</p><p>  this.block

76、Start = blockID * DbForum.THREAD_BLOCK_SIZE;</p><p>  } catch (ForumNotFoundException fnfe) {</p><p>  return null;</p><p><b>  }</b></p><p><b>  }<

77、;/b></p><p>  Object element = null;</p><p>  // 計(jì)算這個(gè)元素在當(dāng)前查詢范圍內(nèi)的相對(duì)位置</p><p>  int relativeIndex = index % DbForum.THREAD_BLOCK_SIZE;</p><p>  // Make sure index isn&

78、#39;t too large</p><p>  if (relativeIndex < threadBlock.length) {</p><p><b>  try {</b></p><p>  // 從緩沖中獲得實(shí)際thread 對(duì)象</p><p>  element = factory.cacheMa

79、nager.threadCache.get(</p><p>  threadBlock[relativeIndex]);</p><p>  } catch (ForumThreadNotFoundException tnfe) { }</p><p><b>  }</b></p><p>  return elem

80、ent;</p><p><b>  }</b></p><p>  ForumThreadBlockIterator是真正實(shí)現(xiàn)分頁(yè)查詢的核心功能,F(xiàn)orumThreadBlockIterator對(duì)象返回到客戶端的過(guò)程中,遭遇ForumThreadIteratorProxy的截獲,可以回頭看看ForumProxy中的threads方法,它最終返回給調(diào)用客戶端Forum

81、.jsp的是ForumThreadIteratorProxy實(shí)例。</p><p>  ForumThreadIteratorProxy也是迭代器ForumThreadIterator的一個(gè)子類,它的一個(gè)具體方法中:</p><p>  public Object next() {</p><p>  return new ForumThreadProxy((For

82、umThread)iterator.next(), authorization,</p><p>  permissions);</p><p><b>  }</b></p><p>  這一句是返回一個(gè)ForumThreadProxy實(shí)例,返回就是一個(gè)ForumThread實(shí)例的代理。這里,Jive使用代理模式實(shí)現(xiàn)訪問(wèn)控制實(shí)現(xiàn)得不是很巧妙,

83、似乎有代理到處“飛”的感覺,這是可以對(duì)之進(jìn)行改造的。</p><p>  從以上可以看出,Jive在輸出如圖3-5所示的多頁(yè)查詢結(jié)果時(shí),采取了下列步驟:</p><p> ?。?)先查詢出符合查詢條件的所有對(duì)象元素的ID集合,注意不是所有對(duì)象元素,只是其ID的集合,這樣節(jié)約了大量?jī)?nèi)存。</p><p> ?。?)每個(gè)頁(yè)面視為一個(gè)Block,每當(dāng)進(jìn)入下一頁(yè)時(shí),獲得下一

84、個(gè)頁(yè)面的所有對(duì)象的ID集合。</p><p> ?。?)輸出當(dāng)前頁(yè)面的所有對(duì)象時(shí),首先從緩沖中獲取,如果緩沖中沒有,再根據(jù)ID從數(shù)據(jù)庫(kù)中獲取完整的對(duì)象數(shù)據(jù)。</p><p>  上述實(shí)現(xiàn)方法完全基于即查即顯,相比于一般批量查詢做法:一次性獲得所有數(shù)據(jù),然后遍歷數(shù)據(jù)結(jié)果集ResultSet,Jive這種批量查詢方式是一種比較理想的選擇。</p><p>  以上是Fo

85、rumThread的批量顯示,有關(guān)帖子內(nèi)容ForumMessage也是采取類似做法。在每個(gè)ForumThread中可能有很多帖子內(nèi)容(ForumMessage對(duì)象集合),也不能在一個(gè)頁(yè)面中全部顯示,所以也是使用迭代模式來(lái)實(shí)現(xiàn)的。顯示一個(gè)Forum主題下所有帖子內(nèi)容的功能由ForumThread的messages()方法完成,檢查它的代理類FroumThreadProxy如何具體完成:</p><p>  publ

86、ic Iterator messages(ResultFilter resultFilter) {</p><p>  Iterator iterator = thread.messages(resultFilter);</p><p>  return new IteratorProxy(JiveGlobals.MESSAGE, iterator, authorization, perm

87、issions);</p><p><b>  }</b></p><p>  實(shí)現(xiàn)的原理基本相同,返回的都是一個(gè)Iterator代理類,在這些代理類中都是進(jìn)行用戶權(quán)限檢驗(yàn)的。</p><p>  Jive中也有關(guān)于一次性獲得所有數(shù)據(jù),然后遍歷ResultSet的做法。這種做法主要適合一次性查詢數(shù)據(jù)庫(kù)的所有數(shù)據(jù),例如查詢當(dāng)前所有論壇Forum,

88、首先實(shí)現(xiàn)SQL語(yǔ)句:</p><p>  SELECT forumID FROM jiveForum</p><p>  獲得所有Forum的forumID,這段代碼位于DbForumFactory.java的forums方法中,如下:</p><p>  public Iterator forums() {</p><p>  if (fo

89、rums == null) {</p><p>  LongList forumList = new LongList();</p><p>  Connection con = null;</p><p>  PreparedStatement pstmt = null;</p><p><b>  try {</b>

90、</p><p>  con = ConnectionManager.getConnection();</p><p>  // GET_FORUMS值是SELECT forumID FROM jiveForum</p><p>  pstmt = con.prepareStatement(GET_FORUMS);</p><p>  Res

91、ultSet rs = pstmt.executeQuery();</p><p>  while (rs.next()) {</p><p>  forumList.add(rs.getLong(1));               

92、60; //將所有查詢ID結(jié)果放入forumList中</p><p><b>  }</b></p><p>  }catch (SQLException sqle) {</p><p>  sqle.printStackTrace();</p><p>  } finally {</p><p&g

93、t;<b>  …</b></p><p><b>  }</b></p><p>  return new DatabaseObjectIterator(JiveGlobals.FORUM, forums, this);</p><p><b>  }</b></p><p>

94、;  forums方法是返回一個(gè)DatabaseObjectIterator,這個(gè)DatabaseObjectIterator也是一個(gè)迭代器,但是實(shí)現(xiàn)原理要比ForumThreadBlockIterator簡(jiǎn)單。它只提供了一個(gè)遍歷指針,在所有ID結(jié)果集中遍歷,然后也是通過(guò)ID獲得完整的數(shù)據(jù)對(duì)象。</p><p>  總之,Jive中關(guān)于批量查詢有兩種實(shí)現(xiàn)方式:以ForumThreadBlockIterator為代

95、表的實(shí)現(xiàn)方式適合在數(shù)據(jù)量巨大、需要多頁(yè)查詢時(shí)使用;而DatabaseObjectIterator則是推薦在一個(gè)頁(yè)面中顯示少量數(shù)據(jù)時(shí)使用。</p><p>  2.6  過(guò)濾器與裝飾模式</p><p>  裝飾(Decorator)模式是動(dòng)態(tài)給一個(gè)對(duì)象添加一些額外的職責(zé),或者說(shuō)改變這個(gè)對(duì)象的一些行為。這就類似于使用油漆為某個(gè)東西刷上油漆,在原來(lái)的對(duì)象表面增加了一層外衣。</

96、p><p>  在裝飾模式中,有兩個(gè)主要角色:一個(gè)是被刷油漆的對(duì)象(decoratee);另外一個(gè)是給decoratee刷油漆的對(duì)象(decorator)。這兩個(gè)對(duì)象都繼承同一個(gè)接口。</p><p>  首先舉一個(gè)簡(jiǎn)單例子來(lái)說(shuō)明什么是裝飾模式。</p><p><b>  先創(chuàng)建一個(gè)接口:</b></p><p>  pu

97、blic interface Work</p><p><b>  { </b></p><p>  public void insert();</p><p><b>  }</b></p><p>  這是一種打樁工作的抽象接口,動(dòng)作insert表示插入,那么插入什么?下面這個(gè)實(shí)現(xiàn)表示方形木樁的

98、插入:</p><p>  public class SquarePeg implements Work{</p><p>  public void insert(){</p><p>  System.out.println("方形樁插入");</p><p><b>  } </b></p

99、><p><b>  }</b></p><p>  本來(lái)這樣也許就可以滿足打樁的工作需要,但是有可能土質(zhì)很硬,在插入方形樁之前先要打一個(gè)洞,那么又將如何實(shí)現(xiàn)?可以編制一個(gè)Decorator類,同樣繼承Work接口,但是在實(shí)現(xiàn)insert方法時(shí)有些特別:</p><p>  public class Decorator implements Wor

100、k{</p><p>  private Work work;</p><p>  //額外增加的功能被打包在這個(gè)List中</p><p>  private ArrayList others = new ArrayList(); </p><p>  public Decorator(Work work)</p><p

101、><b>  {</b></p><p>  this.work=work;</p><p>  others.add("打洞");   //準(zhǔn)備好額外的功能</p><p><b>  }</b></p><p>  public void inser

102、t(){</p><p>  otherMethod();</p><p>  work.insert();</p><p><b>  } </b></p><p>  public void otherMethod()</p><p><b>  {</b></p&

103、gt;<p>  ListIterator listIterator = others.listIterator();</p><p>  while (listIterator.hasNext())</p><p><b>  {</b></p><p>  System.out.println(((String)(listIt

104、erator.next())) + " 正在進(jìn)行");</p><p><b>  }</b></p><p><b>  } </b></p><p><b>  }</b></p><p>  在Decorator的方法insert中先執(zhí)行otherMe

105、thod()方法,然后才實(shí)現(xiàn)SquarePeg的insert方法。油漆工Decorator給被油漆者SquarePeg添加了新的行為——打洞。具體客戶端調(diào)用如下:</p><p>  Work squarePeg = new SquarePeg();</p><p>  Work decorator = new Decorator(squarePeg);</p><p&

106、gt;  decorator.insert();</p><p>  本例中只添加了一個(gè)新的行為(打洞),如果還有很多類似的行為,那么使用裝飾模式的優(yōu)點(diǎn)就體現(xiàn)出來(lái)了。因?yàn)榭梢酝ㄟ^(guò)另外一個(gè)角度(如組織新的油漆工實(shí)現(xiàn)子類)來(lái)對(duì)這些行為進(jìn)行混合和匹配,這樣就不必為每個(gè)行為創(chuàng)建一個(gè)類,從而減少了系統(tǒng)的復(fù)雜性。</p><p>  使用裝飾模式可以避免在被油漆對(duì)象decoratee中包裝很多動(dòng)態(tài)的,

107、可能需要也可能不需要的功能,只要在系統(tǒng)真正運(yùn)行時(shí),通過(guò)油漆工decorator來(lái)檢查那些需要加載的功能,實(shí)行動(dòng)態(tài)加載。</p><p>  Jive論壇實(shí)現(xiàn)了信息過(guò)濾功能。例如可以將帖子內(nèi)容中的HTML語(yǔ)句過(guò)濾掉;可以將帖子內(nèi)容中Java代碼以特別格式顯示等。這些過(guò)濾功能有很多,在實(shí)際使用時(shí)不一定都需要,是由實(shí)際情況選擇的。例如有的論壇就不需要將帖子內(nèi)容的HTML語(yǔ)句過(guò)濾掉,選擇哪些過(guò)濾功能是由論壇管理者具體動(dòng)態(tài)

108、決定的。而且新的過(guò)濾功能可能隨時(shí)可以定制開發(fā)出來(lái),如果試圖強(qiáng)行建立一種接口包含所有過(guò)濾行為,那么到時(shí)有新過(guò)濾功能加入時(shí),還需要改變接口代碼,真是一種危險(xiǎn)的行為。</p><p>  裝飾模式可以解決這種運(yùn)行時(shí)需要?jiǎng)討B(tài)增加功能的問(wèn)題,且看看Jive是如何實(shí)現(xiàn)的。</p><p>  前面討論過(guò),在Jive中,有主要幾個(gè)對(duì)象ForumFactory、Forum以及ForumThread和For

109、umMessage,它們之間的關(guān)系如圖3-2所示。因此帖子內(nèi)容ForumMessage對(duì)象的獲得是從其上級(jí)FroumThread的方法getMessage中獲取,但是在實(shí)際代碼中,F(xiàn)orumThread的方法getMessage委托ForumFactory來(lái)獲取ForumMessage對(duì)象??纯碏orumThread的子類DbForumThread的getMessage代碼:</p><p>  public F

110、orumMessage getMessage(long messageID)</p><p>  throws ForumMessageNotFoundException</p><p><b>  {</b></p><p>  return factory.getMessage(messageID, this.id, forumID);&l

111、t;/p><p><b>  }</b></p><p>  這是一種奇怪的委托,大概是因?yàn)樾枰紤]到過(guò)濾器功能有意為之吧。那就看看ForumFactory的具體實(shí)現(xiàn)子類DbForumFactory的getMessage功能,getMessage是將數(shù)據(jù)庫(kù)中的ForumMessage對(duì)象經(jīng)由過(guò)濾器過(guò)濾一遍后輸出(注:因?yàn)樵瓉?lái)的Jive的getMessage代碼考慮到可緩存

112、或不可緩存的過(guò)濾,比較復(fù)雜,實(shí)際過(guò)濾功能都是可以緩存的,因此精簡(jiǎn)如下)。</p><p>  protected ForumMessage getMessage(long messageID, long threadID, long forumID)</p><p>  throws ForumMessageNotFoundException</p><p><

113、;b>  {</b></p><p>  DbForumMessage message = cacheManager.messageCache.get(messageID);</p><p>  // Do a security check to make sure the message comes from the thread.</p><p&g

114、t;  if (message.threadID != threadID) {</p><p>  throw new ForumMessageNotFoundException();</p><p><b>  }</b></p><p>  ForumMessage filterMessage = null;</p><

115、p><b>  try {</b></p><p>  // 應(yīng)用全局過(guò)濾器</p><p>  filterMessage = filterManager.applyFilters(message);</p><p>  Forum forum = getForum(forumID);    &#

116、160;           </p><p>  //應(yīng)用本論壇過(guò)濾器</p><p>  filterMessage = forum.getFilterManager().applyFilters(filterMessage);</p><p><b>

117、  }</b></p><p>  catch (Exception e) { }</p><p>  return filterMessage;</p><p><b>  }</b></p><p>  上面代碼實(shí)際是裝飾模式的客戶端調(diào)用代碼,DbForumMessage 的實(shí)例message是被油漆者d

118、ecoratee。通過(guò)filterManager 或forum.getFilterManager()的applyFilter方法,將message實(shí)行了所有的過(guò)濾功能。這就類似前面示例的下列語(yǔ)句:</p><p>  Work decorator = new Decorator(squarePeg);</p><p>  forum.getFilterManager()是從數(shù)據(jù)庫(kù)中獲取當(dāng)前

119、配置的所有過(guò)濾器類。每個(gè)Forum都有一套自己的過(guò)濾器類,這是通過(guò)下列語(yǔ)句實(shí)現(xiàn)的:</p><p>  FilterManager filterManager =  new DbFilterManager();</p><p>  在DbFilterManager 的類變量ForumMessageFilter [] filters中保存著所有的過(guò)濾器,applyFilters方法

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論