版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、<p> 2 Jive與設計模式</p><p> Jive論壇系統(tǒng)使用大量設計模式巧妙地實現了一系列功能。因為設計模式的通用性和可理解性,將幫助更多人很快地理解 Jive論壇源碼,從而可以依據一種“協(xié)定”來動態(tài)地擴展它。那么使用設計模式還有哪些好處?</p><p><b> 2.1 設計模式</b></p>&
2、lt;p> 設計模式是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無疑問,設計模式于己于他人于系統(tǒng)都是多贏的。設計模式使代碼編制真正工程化,設計模式是軟件工程的基石。</p><p> GOF(設計模式作者簡稱)《設計模式》這本書第一次將設計模式提升到理論高度,并將之規(guī)范化,該書提出了23種基本設計模式。自此,
3、在可復用面向對象軟件的發(fā)展過程中,新的大量的設計模式不斷出現。</p><p> 很多人都知道Java是完全面向對象的設計和編程語言,但是由于接受教育以及經驗的原因,大多數程序員或設計人員都是從傳統(tǒng)的過程語言轉變而來,因此在思維習慣上要完全轉變?yōu)槊嫦驅ο蟮脑O計和開發(fā)方式是困難的,而學習設計模式可以更好地幫助和堅固這種轉變。</p><p> 凡是學習完成設計模式的人都有一種類似重生的感
4、覺,這種重生可以從很多方面去解釋。換一種新的角度來看待和解決問題應該是一種比較貼切的解釋,而這種新的思維角度培養(yǎng)屬于基礎培訓,因此,設計模式是學習Java的必讀基礎課程之一。</p><p> 由于設計模式概念比較抽象,對于初學者學習有一定的難度,因此結合Jive論壇系統(tǒng)學習設計模式將是一種很好的選擇。</p><p> 掌握了設計模式,將會幫助程序員或設計人員以更加可重用性、可伸縮性
5、的眼光來開發(fā)應用系統(tǒng),甚至開發(fā)通用的框架系統(tǒng)??蚣芟到y(tǒng)是構成一類特定軟件可復用設計的一組相互協(xié)作的類,主要是對應用系統(tǒng)中反復重用部分的提煉,類似一種模板,這是一種結構性的模板。</p><p> 框架通常定義了應用體系的整體結構、類和對象的關系等設計參數,以便于具體應用實現者能集中精力于應用本身的特定細節(jié)??蚣軓娬{設計復用,而設計模式最小的可重用單位,因此框架不可避免地會反復使用到設計模式。關于通用框架系統(tǒng)的設
6、計開發(fā)將在以后章節(jié)中討論。</p><p> 其實Jive論壇本身也形成了一個基于Web結構的通用框架系統(tǒng),因為它很多設計思想是可以重用的,例如設定一個總體入口,通過入口檢查用戶的訪問控制權限,當然還有其他各方面的功能實現方式都是值得在其他系統(tǒng)中借鑒的,也正因為它以模式的形式表現出來,這種可重用性和可借鑒性就更強。</p><p> 2.2 ForumFactory與工廠模
7、式</p><p> 工廠模式是GOF設計模式的主要常用模式,它主要是為創(chuàng)建對象提供了一種接口,工廠模式主要是封裝了創(chuàng)建對象的細節(jié)過程,從而使得外界調用一個對象時,根本無需關心這個對象是如何產生的。</p><p> 在GOF設計模式中,工廠模式分為工廠方法模式和抽象工廠模式。兩者主要區(qū)別是,工廠方法是創(chuàng)建一種產品接口下的產品對象,而抽象工廠模式是創(chuàng)建多種產品接口下的產品對象,非常類似
8、Builder生成器模式。在平時實踐中,使用較多的基本是工廠方法模式。</p><p> 以類SampleOne為例,要創(chuàng)建SampleOne的對象實例:</p><p> SampleOne sampleOne = new SampleOne();</p><p> 如果Sample類有幾個相近的類:SampleTwo或SampleThree,那么創(chuàng)建它們的
9、實例分別是:</p><p> SampleTwo sampleTwo = new SampleTwo();</p><p> SampleThree sampleThree = new SampleThree();</p><p> 其實這3個類都有一些共同的特征,如網上商店中銷售書籍、玩具或者化妝品。雖然它們是不同的具體產品,但是它們有一個共同特征,可以抽
10、象為“商品”。日常生活中很多東西都可以這樣高度抽象成一種接口形式。上面這3個類如果可以抽象為一個統(tǒng)一接口SampleIF,那么上面語句就可以成為:</p><p> SampleIF sampleOne = new SampleOne();</p><p> SampleIF sampleTwo = new SampleTwo();</p><p> Samp
11、leIF sampleThree = new SampleThree();</p><p> 在實際情況中,有時并不需要同時生成3種對象,而是根據情況在3者之中選一個。在這種情況下,需要使用工廠方法來完成了,創(chuàng)建一個叫SampleFactory的抽象類:</p><p> public class SampleFactory{</p><p> public
12、abstract SampleIF creator();</p><p><b> }</b></p><p> 在這個抽象工廠類中有一個抽象方法creator,但是沒有具體實現,而是延遲到它的子類中實現,創(chuàng)建子類SampleFactoryImp:</p><p> public class SampleFactoryImp extend
13、s SampleFactory{</p><p> public SampleIF creator(){</p><p> //根據其他因素綜合判斷返回具體產品</p><p> //假設應該返回SampleOne對象</p><p> return new SampleOne();</p><p><b
14、> }</b></p><p><b> }</b></p><p> 在SampleFactoryImp中根據具體情況來選擇返回SampleOne、SampleTwo或SampleThree。所謂具體情況有很多種:上下文其他過程計算結果;直接根據配置文件中配置。</p><p> 上述工廠方法模式中涉及到一個抽象產品
15、接口Sample,如果還有其他完全不同的產品接口,如Product等,一個子類SampleFactoryImp只能實現一套系列產品方案的生產,如果還需要另外一套系統(tǒng)產品方案,就可能需要另外一個子類SampleFactoryImpTwo來實現。這樣,多個產品系列、多個工廠方法就形成了抽象工廠模式。</p><p> 前面已經討論在Jive中設置了論壇統(tǒng)一入口,這個統(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> ... //從配置文件中獲得當前className</p><p><b> try {</b></p><p><b> //動態(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.用來限制授權對forum的訪問</p><p> return new ForumFactoryProxy(authorization, factory,factory.getPermissions(authorization));</p><p><b> }</b></p><p> //創(chuàng)鍵產品接口Forum的具體對象實例&
23、lt;/p><p> public abstract Forum createForum(String name, String description)</p><p> throws UnauthorizedException, ForumAlreadyExistsException;</p><p> //創(chuàng)鍵產品接口ForumThread的具體對象實例&l
24、t;/p><p> public abstract ForumThread createThread(ForumMessage rootMessage) </p><p> throws UnauthorizedException;</p><p> //創(chuàng)鍵產品接口ForumMessage的具體對象實例</p><p> public
25、abstract ForumMessage createMessage();</p><p><b> ....</b></p><p><b> }</b></p><p> ForumFactory中提供了很多抽象方法如createForum、createThread和createMessage()等,它們是創(chuàng)建
26、各自產品接口下的具體對象,這3個接口就是前面分析的基本業(yè)務對象Forum、ForumThread和ForumMessage,這些創(chuàng)建方法在ForumFactory中卻不立即執(zhí)行,而是推遲到ForumFactory子類中實現。</p><p> ForumFactory的子類實現是com.Yasna.forum.database.DbForumFactory,這是一種數據庫實現方式。即在DbForumFactor
27、y中分別實現了在數據庫中createForum、createThread和createMessage()等3種方法,當然也提供了動態(tài)擴展到另外一套系列產品的生產方案的可能。如果使用XML來實現,那么可以編制一個XmlForumFactory的具體工廠子類來分別實現3種創(chuàng)建方法。</p><p> 因此,Jive論壇在統(tǒng)一入口處使用了抽象工廠模式來動態(tài)地創(chuàng)建論壇中所需要的各種產品,如圖3-4所示。</p&g
28、t;<p> 圖3-4 ForumFactory抽象工廠模式圖</p><p> 圖3-4中,XmlForumFactory和DbForumFactory作為抽象工廠ForumFactory的兩個具體實現,而Forum、ForumThread和ForumMessage分別作為3個系列抽象產品接口,依靠不同的工廠實現方式,會產生不同的產品對象。</p><p>
29、 從抽象工廠模式去理解Jive論壇統(tǒng)一入口處,可以一步到位掌握了幾個類之間的大概關系。因為使用了抽象工廠模式這種通用的設計模式,可以方便源碼閱讀者快速地掌握整個系統(tǒng)的結構和來龍去脈,圖3-4這張圖已經初步展示了Jive的主要框架結構。</p><p> 細心的讀者也許會發(fā)現,在上面ForumFactory有一個getInstance比較令人費解,這將在2.3節(jié)進行討論。</p><p>
30、; 2.3 統(tǒng)一入口與單態(tài)模式</p><p> 在上面ForumFactory的getInstance方法使用單態(tài)(SingleTon)模式。單態(tài)模式是保證一個類有且僅有一個對象實例,并提供一個訪問它的全局訪問點。</p><p> 前面曾提到ForumFactory是Jive提供客戶端訪問數據庫系統(tǒng)的統(tǒng)一入口。為了保證所有的客戶端請求都要經過這個ForumFactor
31、y,如果不使用單態(tài)模式,客戶端下列調用語句表示生成了ForumFactory實例:</p><p> ForumFactory factory = new DbForumFactory();</p><p> 客戶端每發(fā)生一次請求都調用這條語句,這就會發(fā)生每次都生成不同factory對象實例,這顯然不符合設計要求,因此必須使用單態(tài)模式。</p><p> 一般
32、在Java實現單態(tài)模式有幾種選擇,最常用而且安全的用法如下:</p><p> public class Singleton { </p><p> private Singleton(){}</p><p> //在自己內部定義自己一個實例,是不是很奇怪</p><p> //注意這是private,只供內部調用</p>
33、<p> private static Singleton instance = new Singleton(); </p><p> //這里提供了一個供外部訪問本class的靜態(tài)方法,可以直接訪問</p><p> public static Singleton getInstance() { </p><p> return instan
34、ce; </p><p><b> } </b></p><p><b> }</b></p><p> 單態(tài)模式一共使用了兩條語句實現:第一條直接生成自己的對象,第二條提供一個方法供外部調用這個對象,同時最好將構造函數設置為private,以防止其他程序員直接使用new Singleton生成實例。</p&g
35、t;<p> 還有一種Java單態(tài)模式實現:</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> 在上面代碼中,使用了判斷語句。如果instance為空,再進行實例化,這成為lazy initialization。注意getInstance()方法的synchronized,這個synchronized很重要。如果沒有synchronized,那么使用getInstance()在第一次被訪問時有可能得到多個Si
38、ngleton實例。</p><p> 關于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的討論,有興趣者可以進一步研究。一般認為第一種形式要更加安全些;但是后者可以用在類初始化時需要參數輸入的情況下。</p><p> 在Jive的ForumFactory中采取了后者lazy initialization形
39、式,這是為了能夠動態(tài)配置指定ForumFactory的具體子類。在getInstance中,從配置文件中獲得當前工廠的具體實現,如果需要啟動XmlForumFactory,就不必修改ForumFactory代碼,直接在配置文件中指定className的名字為XmlForumFactory。這樣通過下列動態(tài)裝載機制生成ForumFactory具體對象:</p><p> Class c = Class.forNa
40、me(className);</p><p> factory = (ForumFactory)c.newInstance();</p><p> 這是利用Java的反射機制,可以通過動態(tài)指定className的數值而達到生成對象的方式。</p><p> 使用單態(tài)模式的目標是為了控制對象的創(chuàng)建,單態(tài)模式經常使用在控制資源的訪問上。例如數據庫連接或Socket
41、連接等。單態(tài)模式可以控制在某個時刻只有一個線程訪問資源。由于Java中沒有全局變量的概念,因此使用單態(tài)模式有時可以起到這種作用,當然需要注意是在一個JVM中。</p><p> 2.4 訪問控制與代理模式</p><p> 仔細研究會發(fā)現,在ForumFactory的getInstance方法中最后的返回值有些奇怪。按照單態(tài)模式的概念應該直接返回factory這個對象實例,
42、但是卻返回了ForumFactoryProxy的一個實例,這實際上改變了單態(tài)模式的初衷。這樣客戶端每次通過調用ForumFactory的getInstance返回的就不是ForumFactory的惟一實例,而是新的對象。之所以這樣做是為了訪問權限的控制,姑且不論這樣做的優(yōu)劣,先看看什么是代理模式。</p><p> 代理模式是屬于設計模式結構型模式中一種,它是實際訪問對象的代理對象,或者影子對象,主要達到控制實
43、際對象的訪問。這種控制的目的很多,例如提高性能等。即遠程代理模式,這種模式將在以后章節(jié)討論。</p><p> 其中一個主要的控制目的是控制客戶端對實際對象的訪問權限。在Jive系統(tǒng)中,因為有角色權限的分別,對于Forum、ForumThread和FroumMessage的訪問操作必須經過權限機制驗證后才能進行。</p><p> 以ForumFactoryProxy中的createF
44、orum方法為例,其實ForumFactoryProxy也是FroumFactory的一種工廠實現,它的createForum具體實現如下:</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> 在這個方法中進行了權限驗證,判斷是否屬于系統(tǒng)管理員。如果是,將直接從DbForumFactory對象factory的方法createForum中獲得一個新的Forum對象,然后再返回Forum的子類代理對象ForumProx
48、y。因為在Forum中也還有很多屬性和操作方法,這些也需要進行權限驗證。ForumProxy和ForumFactoryProxy起到類似的作用。</p><p> Jive中有下列幾個代理類:</p><p> ? ForumFactoryProxy:客戶端和DbForumFac
49、tory之間的代理??蛻舳嗽L問DbForumFactory的任何方法都要先經過ForumFactoryProxy相應方法代理一次。以下意思相同。</p><p> ? ForumProxy:客戶端和DbForum之間的代理,研究Forum對象的每個方法,必須先看ForumProxy對象的方法。</p
50、><p> ? ForumMessageProxy:客戶端和DbForumMessage之間的代理。</p><p> ? ForumThreadProxy:客戶端和DbFor
51、umThread之間的代理。</p><p> User和Group也有相應的代理類。</p><p> 由以上分析看出,每個數據對象都有一個代理。如果系統(tǒng)中數據對象非常多,依據這種一對一的代理關系,會有很多代理類,將使系統(tǒng)變得不是非常干凈,因此可以使用動態(tài)代理來代替這所有的代理類,具體實現將在以后章節(jié)討論。</p><p> 2.5 批量分頁查詢
52、與迭代模式</p><p> 迭代(Iterator)模式是提供一種順序訪問某個集合各個元素的方法,確保不暴露該集合的內部表現。迭代模式應用于對大量數據的訪問,Java Collection API中Iterator就是迭代模式的一種實現。</p><p> 在前面章節(jié)已經討論過,用戶查詢大量數據,從數據庫不應該直接返回ResultSet,應該是Collection。但是有一個問題,如
53、果這個數據很大,需要分頁面顯示。如果一下子將所有頁面要顯示的數據都查詢出來放在Collection,會影響性能。而使用迭代模式則不必將全部集合都展現出來,只有遍歷到某個元素時才會查詢數據庫獲得這個元素的數據。</p><p> 以論壇中顯示帖子主題為例,在一個頁面中不可能顯示所有主題,只有分頁面顯示,如圖3-5所示。</p><p> 圖3-5中一共分15頁來顯示所有論壇帖子,可以從顯
54、示Forum.jsp中發(fā)現下列語句可以完成上述結果:</p><p> ResultFilter filter = new ResultFilter(); //設置結果過濾器</p><p> filter.setStartIndex(start);
55、60; //設置開始點</p><p> filter.setNumResults(range); //設置范圍</p><p> ForumThreadIterator threads = forum.threads(filter); //獲得迭代器&l
56、t;/p><p> while(threads.hasNext){</p><p> //逐個顯示threads中帖子主題,輸出圖3-5中的每一行 </p><p><b> }</b></p><p> 圖3-5 分頁顯示所有帖子</p><p> 上述代碼中主要是從Forum
57、的threads方法獲得迭代器ForumThreadIterator的實例,依據前面代理模式中分析、研究Forum對象的方法,首先是看ForumProxy中對應方法,然后再看DbForum中對應方法的具體實現。在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> 首先是調用了DbForum中具體的threads方法,再追蹤到DbForum中看看,它的threads方法代碼如下:</p><p> public ForumThreadIterator threads(ResultFilter resultFilter) {</p><p> //按resultFilter設置范圍要求獲得SQL查詢語句&l
60、t;/p><p> String query = getThreadListSQL(resultFilter, false); </p><p> //獲得resultFilter設置范圍內的所有ThreadID集合</p><p> long [] threadBlock = getThreadBlock(query.toString(), resu
61、ltFilter.getStartIndex());</p><p> //以下是計算查詢區(qū)域的開始點和終點</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是一個查詢結果類,
65、可以對論壇主題Thread和帖子內容Message進行過濾或排序,這樣就可以根據用戶要求定制特殊的查詢范圍。如查詢某個用戶去年在這個論壇發(fā)表的所有帖子,那只要創(chuàng)建一個ResultFilter對象就可以代表這個查詢要求。</p><p> 在上面threads方法代碼中,第一步是先定制出相應的動態(tài)SQL查詢語句,然后使用這個查詢語句查詢數據庫,獲得查詢范圍內所有的ForumThread的ID集合,然后在這個ID集
66、合中獲得當前頁面的ID子集合,這是非常關鍵的一步。</p><p> 在這關鍵的一步中,有兩個重要的方法getThreadListSQL和getThreadBlock:</p><p> ? GetThreadListSQL:獲得SQL查詢語句query的值,這個方法Jive實現
67、起來顯得非常地瑣碎。</p><p> ? GetThreadBlock:獲得當前頁面的ID子集合,那么如何確定ID子集合的開始位置呢?查看getThreadBlock方法代碼,可以發(fā)現,它是使用最普遍的ResultSet next()方法來逐個跳躍到開始位置。</p><p>
68、 上面代碼的Threads方法中最后返回的是ForumThreadBlockIterator,它是抽象類ForumThreadIterator的子類,而ForumThreadIterator繼承了Collection的Iterator,以此聲明自己是一個迭代器,ForumMessageBlockIterator實現的具體方法如下:</p><p> public boolean hasNext();
69、 //判斷是否有下一個元素</p><p> public boolean hasPrevious() //判斷是否有前一個元素</p><p> public Object next() throws java.util.NoSuchElementException //獲得下一個元素實例</p><p&
70、gt; ForumThreadBlockIterator中的Block是“頁”的意思,它的一個主要類變量threadBlock包含的是一個頁面中所有ForumThread的ID,next()方法實際是對threadBlock中ForumThread進行遍歷,如果這個頁面全部遍歷完成,將再獲取下一頁(Block)數據。</p><p> 在ForumThreadBlockIterator重要方法getEleme
71、nt中實現了兩個功能:</p><p> ? 如果當前遍歷指針超過當前頁面,將使用getThreadBlock獲得下一個頁面的ID子集合;</p><p> ? 如果當前遍
72、歷指針在當前頁面之內,根據ID獲得完整的數據對象,實現輸出;</p><p> ForumThreadBlockIterator的getElement方法代碼如下:</p><p> private Object getElement(int index) {</p><p> if (index < 0) {
73、0; return null; }</p><p> // 檢查所要獲得的 element 是否在本查詢范圍內(當前頁面內)</p><p> if (index < blockStart || </p><p> index >
74、= blockStart + DbForum.THREAD_BLOCK_SIZE) { </p><p><b> try {</b></p><p> //從緩沖中獲得Forum實例</p><p> DbForum forum = factory.cacheManager.forumCache.get(foru
75、mID);</p><p> //獲得下一頁的內容</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> // 計算這個元素在當前查詢范圍內的相對位置</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> // 從緩沖中獲得實際thread 對象</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是真正實現分頁查詢的核心功能,ForumThreadBlockIterator對象返回到客戶端的過程中,遭遇ForumThreadIteratorProxy的截獲,可以回頭看看ForumProxy中的threads方法,它最終返回給調用客戶端Forum
81、.jsp的是ForumThreadIteratorProxy實例。</p><p> ForumThreadIteratorProxy也是迭代器ForumThreadIterator的一個子類,它的一個具體方法中:</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> 這一句是返回一個ForumThreadProxy實例,返回就是一個ForumThread實例的代理。這里,Jive使用代理模式實現訪問控制實現得不是很巧妙,
83、似乎有代理到處“飛”的感覺,這是可以對之進行改造的。</p><p> 從以上可以看出,Jive在輸出如圖3-5所示的多頁查詢結果時,采取了下列步驟:</p><p> ?。?)先查詢出符合查詢條件的所有對象元素的ID集合,注意不是所有對象元素,只是其ID的集合,這樣節(jié)約了大量內存。</p><p> ?。?)每個頁面視為一個Block,每當進入下一頁時,獲得下一
84、個頁面的所有對象的ID集合。</p><p> ?。?)輸出當前頁面的所有對象時,首先從緩沖中獲取,如果緩沖中沒有,再根據ID從數據庫中獲取完整的對象數據。</p><p> 上述實現方法完全基于即查即顯,相比于一般批量查詢做法:一次性獲得所有數據,然后遍歷數據結果集ResultSet,Jive這種批量查詢方式是一種比較理想的選擇。</p><p> 以上是Fo
85、rumThread的批量顯示,有關帖子內容ForumMessage也是采取類似做法。在每個ForumThread中可能有很多帖子內容(ForumMessage對象集合),也不能在一個頁面中全部顯示,所以也是使用迭代模式來實現的。顯示一個Forum主題下所有帖子內容的功能由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> 實現的原理基本相同,返回的都是一個Iterator代理類,在這些代理類中都是進行用戶權限檢驗的。</p><p> Jive中也有關于一次性獲得所有數據,然后遍歷ResultSet的做法。這種做法主要適合一次性查詢數據庫的所有數據,例如查詢當前所有論壇Forum,
88、首先實現SQL語句:</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結果放入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方法是返回一個DatabaseObjectIterator,這個DatabaseObjectIterator也是一個迭代器,但是實現原理要比ForumThreadBlockIterator簡單。它只提供了一個遍歷指針,在所有ID結果集中遍歷,然后也是通過ID獲得完整的數據對象。</p><p> 總之,Jive中關于批量查詢有兩種實現方式:以ForumThreadBlockIterator為代
95、表的實現方式適合在數據量巨大、需要多頁查詢時使用;而DatabaseObjectIterator則是推薦在一個頁面中顯示少量數據時使用。</p><p> 2.6 過濾器與裝飾模式</p><p> 裝飾(Decorator)模式是動態(tài)給一個對象添加一些額外的職責,或者說改變這個對象的一些行為。這就類似于使用油漆為某個東西刷上油漆,在原來的對象表面增加了一層外衣。</
96、p><p> 在裝飾模式中,有兩個主要角色:一個是被刷油漆的對象(decoratee);另外一個是給decoratee刷油漆的對象(decorator)。這兩個對象都繼承同一個接口。</p><p> 首先舉一個簡單例子來說明什么是裝飾模式。</p><p><b> 先創(chuàng)建一個接口:</b></p><p> pu
97、blic interface Work</p><p><b> { </b></p><p> public void insert();</p><p><b> }</b></p><p> 這是一種打樁工作的抽象接口,動作insert表示插入,那么插入什么?下面這個實現表示方形木樁的
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> 本來這樣也許就可以滿足打樁的工作需要,但是有可能土質很硬,在插入方形樁之前先要打一個洞,那么又將如何實現?可以編制一個Decorator類,同樣繼承Work接口,但是在實現insert方法時有些特別:</p><p> public class Decorator implements Wor
100、k{</p><p> private Work work;</p><p> //額外增加的功能被打包在這個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("打洞"); //準備好額外的功能</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())) + " 正在進行");</p><p><b> }</b></p><p><b> } </b></p><p><b> }</b></p><p> 在Decorator的方法insert中先執(zhí)行otherMe
105、thod()方法,然后才實現SquarePeg的insert方法。油漆工Decorator給被油漆者SquarePeg添加了新的行為——打洞。具體客戶端調用如下:</p><p> Work squarePeg = new SquarePeg();</p><p> Work decorator = new Decorator(squarePeg);</p><p&
106、gt; decorator.insert();</p><p> 本例中只添加了一個新的行為(打洞),如果還有很多類似的行為,那么使用裝飾模式的優(yōu)點就體現出來了。因為可以通過另外一個角度(如組織新的油漆工實現子類)來對這些行為進行混合和匹配,這樣就不必為每個行為創(chuàng)建一個類,從而減少了系統(tǒng)的復雜性。</p><p> 使用裝飾模式可以避免在被油漆對象decoratee中包裝很多動態(tài)的,
107、可能需要也可能不需要的功能,只要在系統(tǒng)真正運行時,通過油漆工decorator來檢查那些需要加載的功能,實行動態(tài)加載。</p><p> Jive論壇實現了信息過濾功能。例如可以將帖子內容中的HTML語句過濾掉;可以將帖子內容中Java代碼以特別格式顯示等。這些過濾功能有很多,在實際使用時不一定都需要,是由實際情況選擇的。例如有的論壇就不需要將帖子內容的HTML語句過濾掉,選擇哪些過濾功能是由論壇管理者具體動態(tài)
108、決定的。而且新的過濾功能可能隨時可以定制開發(fā)出來,如果試圖強行建立一種接口包含所有過濾行為,那么到時有新過濾功能加入時,還需要改變接口代碼,真是一種危險的行為。</p><p> 裝飾模式可以解決這種運行時需要動態(tài)增加功能的問題,且看看Jive是如何實現的。</p><p> 前面討論過,在Jive中,有主要幾個對象ForumFactory、Forum以及ForumThread和For
109、umMessage,它們之間的關系如圖3-2所示。因此帖子內容ForumMessage對象的獲得是從其上級FroumThread的方法getMessage中獲取,但是在實際代碼中,ForumThread的方法getMessage委托ForumFactory來獲取ForumMessage對象??纯碏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> 這是一種奇怪的委托,大概是因為需要考慮到過濾器功能有意為之吧。那就看看ForumFactory的具體實現子類DbForumFactory的getMessage功能,getMessage是將數據庫中的ForumMessage對象經由過濾器過濾一遍后輸出(注:因為原來的Jive的getMessage代碼考慮到可緩存
112、或不可緩存的過濾,比較復雜,實際過濾功能都是可以緩存的,因此精簡如下)。</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> // 應用全局過濾器</p><p> filterMessage = filterManager.applyFilters(message);</p><p> Forum forum = getForum(forumID);
116、160; </p><p> //應用本論壇過濾器</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> 上面代碼實際是裝飾模式的客戶端調用代碼,DbForumMessage 的實例message是被油漆者d
118、ecoratee。通過filterManager 或forum.getFilterManager()的applyFilter方法,將message實行了所有的過濾功能。這就類似前面示例的下列語句:</p><p> Work decorator = new Decorator(squarePeg);</p><p> forum.getFilterManager()是從數據庫中獲取當前
119、配置的所有過濾器類。每個Forum都有一套自己的過濾器類,這是通過下列語句實現的:</p><p> FilterManager filterManager = new DbFilterManager();</p><p> 在DbFilterManager 的類變量ForumMessageFilter [] filters中保存著所有的過濾器,applyFilters方法
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- java種設計模式總結
- java23種設計模式(總結)
- java設計模式瘋狂java聯(lián)盟版
- java設計模式之外觀
- java23種設計模式
- java幾種模式
- java課程設計---基于java的坦克大戰(zhàn)
- 基于JAVA語言的設計模式識別的研究與應用.pdf
- java課程設計----基于java的坦克大戰(zhàn)
- java從菜鳥到高手之設計模式
- 基于IDE模式的Java實驗平臺研究.pdf
- 基于java課設設計
- java從菜鳥到高手之設計模式
- 用Java泛型實現設計模式.pdf
- 畢業(yè)設計----基于bs模式的java在線考試系統(tǒng)的設計與實現
- 基于Java與Web模式的教務管理系統(tǒng)的設計與實現.pdf
- java課程設計--基于java的24點游戲
- java課程設計--基于java的掃雷游戲軟件設計
- 基于java會議管理系統(tǒng)設計
- 基于java的cs模式網絡聊天室的
評論
0/150
提交評論