Java設(shè)計(jì)模式之策略模式篇(摘)
Java設(shè)計(jì)模式之策略模式篇 |
作者:馮睿 本文選自:賽迪網(wǎng) 2003年02月27日 |
策略模式(Strategy Pattern)中體現(xiàn)了兩個(gè)非常基本的面向?qū)ο笤O(shè)計(jì)的基本原則:封裝變化的概念;編程中使用接口,而不是對(duì)接口實(shí)現(xiàn)。策略模式的定義如下: 定義一組算法,將每個(gè)算法都封裝起來(lái),并且使它們之間可以互換。策略模式使這些算法在客戶端調(diào)用它們的時(shí)候能夠互不影響地變化。 策略模式使開(kāi)發(fā)人員能夠開(kāi)發(fā)出由許多可替換的部分組成的軟件,并且各個(gè)部分之間是弱連接的關(guān)系。弱連接的特性使軟件具有更強(qiáng)的可擴(kuò)展性,易于維護(hù);更重要的是,它大大提高了軟件的可重用性。 為了說(shuō)明策略模式,我們將首先討論一下在Swing中是如何利用策略模式來(lái)繪制組件邊界的,然后討論在Swing中使用策略模式帶來(lái)的好處,最后討論如何在軟件中實(shí)現(xiàn)策略模式。 對(duì)所有的Swing組件,例如按鈕、列表單等,都還可以繪制邊框。在Swing中提供了各種邊框類型,例如bevel、etched、line、titled等。Swing組件的邊框是通過(guò)JComponent類來(lái)繪制的,該類是所有Swing組件的基類,實(shí)現(xiàn)了所有Swing組件公共的功能。在JComponent中有一個(gè)paintBorder()方法,該方法為組件繪制邊框。Swing的開(kāi)發(fā)人員可以象下面的例子中所示那樣來(lái)繪制邊框:
請(qǐng)注意上面的代碼只是一種假設(shè),事實(shí)上Swing的開(kāi)發(fā)人員并沒(méi)有這樣實(shí)現(xiàn)paintBorder()方法。在上面的代碼中,在JComponent中繪制邊框的代碼被直接寫(xiě)入了paintBorder()方法中,這意味著JComponent和繪制邊框的功能被緊密地結(jié)合在了一起。很自然地大家會(huì)聯(lián)想到如果需要實(shí)現(xiàn)一種新的邊框類型,開(kāi)發(fā)人員必須修改至少三處代碼:首先增加一個(gè)常量,該常量代表新添加的邊框的類型值;其次需要在Switch語(yǔ)句中增加一個(gè)case語(yǔ)句;最后開(kāi)發(fā)人員需要實(shí)現(xiàn)paintXXXBorder()方法,其中XXX代表新邊框的名稱。 很顯然要擴(kuò)展上面paintBorder()方法的功能是一件很困難的事情,不僅僅是因?yàn)殚_(kāi)發(fā)人員需要增加一種新的邊框類型,更麻煩的是開(kāi)發(fā)人員很難修改JComponent類。JComponent類已經(jīng)被編譯到了Swing的開(kāi)發(fā)工具中,如果開(kāi)發(fā)人員想修改它的話,必須獲得Swing的源代碼,修改后重新編譯Swing。同時(shí)在用戶的計(jì)算機(jī)上與需要使用新編譯的Swing API。另外所有的Swing組件都可以使用開(kāi)發(fā)人員新添加的邊框類型。有可能開(kāi)發(fā)人員只希望新的邊框被某些組件使用,但是現(xiàn)在開(kāi)發(fā)人員無(wú)法對(duì)使用該邊框的組件進(jìn)行限制。 開(kāi)發(fā)人員有更好的實(shí)現(xiàn)方法嗎?答案就是策略模式。通過(guò)策略模式,可以將JComponent和實(shí)現(xiàn)繪制邊框的代碼分離開(kāi)來(lái),這樣開(kāi)發(fā)人員在增加或修改繪制邊框的代碼使就不需要修改JComponent的代碼。通過(guò)應(yīng)用策略模式,開(kāi)發(fā)人員將變化的概念(在這個(gè)例子中是繪制邊框)封裝起來(lái),然后通過(guò)一個(gè)Border接口,使程序能夠重用繪制邊框的功能。下面讓我們來(lái)看JComponent是如何利用策略模式來(lái)實(shí)現(xiàn)繪制邊框的功能的:
上面的paintBorder()方法通過(guò)一個(gè)border對(duì)象繪制了組件的邊框。這樣border對(duì)象替代了前一個(gè)例子中的JComponent封裝了邊框繪制的功能。我們還應(yīng)該注意到JComponent將一個(gè)對(duì)自己的引用傳遞給了Border.paintBorder()方法,這是因?yàn)锽order的實(shí)例必須知道它對(duì)應(yīng)的組件的信息,這種方式通常被稱為委托。通過(guò)這種方式,一個(gè)對(duì)象可以將功能委托給另一個(gè)對(duì)象來(lái)實(shí)現(xiàn)。 在JComponent類中引用了一個(gè)Border對(duì)象,通過(guò)JComponent.getBorder()方法可以獲得該Border對(duì)象。下面的代碼演示了如何設(shè)定和獲得Border對(duì)象:
當(dāng)開(kāi)發(fā)人員通過(guò)JComponent.setBorder()方法設(shè)定了一個(gè)組件的邊框后,JComponent類發(fā)出一個(gè)屬性更新事件。如果新的邊框和以前的邊框不同的話,setBorder()方法就重新繪制邊框。getBorder()方法僅僅返回對(duì)Border對(duì)象的引用。圖1顯示了Border的類結(jié)構(gòu)圖: ![]() 通過(guò)類結(jié)構(gòu)圖我們可以看到,JComponent類中保存了一個(gè)對(duì)Border對(duì)象的引用。由于Border是一個(gè)接口,Swing組件可以使用任何一個(gè)實(shí)現(xiàn)了Border接口的類。 現(xiàn)在我們已經(jīng)知道了JComponent是如何利用策略模式來(lái)繪制組件的邊框的。下面讓我們通過(guò)實(shí)現(xiàn)一個(gè)新的邊框類型來(lái)測(cè)試一下它的可擴(kuò)展性。 圖2中是一個(gè)有三個(gè)JPanel對(duì)象的小程序,每個(gè)JPanel對(duì)象有各自不同的邊框,每個(gè)邊框?qū)?yīng)一個(gè)HandleBorder實(shí)例。 ![]()
HandleBorder類繼承了javax.swing.border.AbstractBorder類并重寫(xiě)了paintBorder()和getBorderInsets()。HandleBorder是如何實(shí)現(xiàn)的其實(shí)并不重要,重要的是由于Swing使用了策略模型,開(kāi)發(fā)人員能夠很方便地增加新的邊框類型。下面的代碼顯示了如何使用HandleBorder類。在這個(gè)例子中創(chuàng)建了三個(gè)JPanel對(duì)象,并對(duì)每個(gè)JPanel對(duì)象設(shè)定一個(gè)HandleBorder實(shí)例作為邊框。
還記得在上面的例子中曾提到在有些情況下,對(duì)組件的引用會(huì)作為參數(shù)傳遞給Border.paintBorder()方法。雖然上面的HandleBorder類沒(méi)有保存對(duì)組件的引用,但是有些情況下Border接口的實(shí)現(xiàn)類會(huì)使用到對(duì)組件的引用并從中獲得關(guān)于組件的信息。例如在EtchedBorder中,paintBorder()方法通過(guò)對(duì)組件的引用獲得它對(duì)應(yīng)的組件的陰影和高光色:
通過(guò)以下步驟,開(kāi)發(fā)人員可以很容易地在軟件中實(shí)現(xiàn)策略模型: 1.對(duì)策略對(duì)象定義一個(gè)公共接口。 2.編寫(xiě)策略類,該類實(shí)現(xiàn)了上面的公共接口。 3.在使用策略對(duì)象的類中保存一個(gè)對(duì)策略對(duì)象的引用。 4.在使用策略對(duì)象的類中,實(shí)現(xiàn)對(duì)策略對(duì)象的set和get方法。 在Swing邊框的例子中,公共接口是javax.swing.Border。策略類是LineBorder、EtchedBorder、HandleBorder等。而使用策略對(duì)象的類是JComponent。 |
posted on 2005-12-24 10:09 beyondduke 閱讀(576) 評(píng)論(0) 編輯 收藏 所屬分類: 我的收藏