设计模式- 策略模式
在開始說設計模式之前,讓我們先聊點別的東西,相信每個人都有自己難忘的童年時光,在那時有很多有趣好玩的事物陪伴著我們。我記得小時候,很喜歡看一部動畫片--《四驅兄弟》,,,好吧暴露年紀了。。受動畫片的影響,還經常和小伙伴們一起買四驅玩具車玩。除了玩具車外,我還喜歡玩游戲機來打發時間,當然不是你想的那種游戲主機什么的,而是這種:
?
手持游戲機
。。可能現在有些小伙伴不認識這家伙了,這其實就是一個手持的小型游戲機,里面內置了幾種游戲,我能夠想起的幾種游戲一個是比較經典的俄羅斯方塊,還有個是很簡單的賽車游戲,就是在游戲中不斷躲避障礙物,并且速度還會不斷加快。種類還是比較少的。好了言歸正傳,一般工廠生產產品時,都需要一個模具,或者說一套標準,在生產具體的產品時,都得照著這個標準做。好了,那么生產這個游戲機的標準是怎樣的呢,我們可以定義一個類來描述這個標準:
/*** 工廠中制作游戲機的一個模型標準(類似于模具)*/ public abstract class GamePlayerModel { // 每個游戲機都內置一款游戲,具體游戲類型在生產具體的游戲機時裝入abstract void game(); // 游戲機外觀,具體在生產時決定abstract void display(); // 點擊游戲機上的開始游戲按鈕進入游戲public void startGame(){game();} }可以看到,在這個游戲機模具中,內置了一款游戲(這里假設每個游戲機中只有一款游戲),當然開始什么也沒裝,只有在生產具體類型的游戲機時才會裝入相應的游戲,還有個開始游戲的方法,當點擊開始游戲就會調用內置的游戲。里面還有個display方法,表示游戲機的外觀,具體是什么顏色,也只有在生產時才能決定。當然這里的模型我們是經過簡化的,事實上要復雜很多。
好了有了這個游戲機模型,我們生產一個游戲機就很方便了,比如我們需要生產一個紅色的內置俄羅斯方塊游戲的游戲機,我們定義一個類來描述:
public class RedTetrisPlayer extends GamePlayerModel{@Overridevoid game() {System.out.print("正在俄羅斯方塊游戲中...");}@Overridevoid display() {System.out.print("一臺紅色的游戲機");} }可以看到,有了之前游戲機模型標準的基礎,我們需要一臺有俄羅斯方塊游戲的游戲機時,在生產時裝入這款游戲并給游戲機上了顏色。
接下來我們就試試這款游戲機好不好用:
public class TestClient {public static void main(String[] args){ // 一臺新鮮出爐的紅色的游戲機RedTetrisPlayer tetrisGamePlayer = new RedTetrisPlayer(); // 點擊游戲機上的開始游戲按鈕tetrisGamePlayer.startGame();} }代碼執行結果: --------------------------------------------------------------------------------------------------------------------- 正在俄羅斯方塊游戲中... ---------------------------------------------------------------------------------------------------------------------可以看到,俄羅斯方塊游戲已經啟動,是不是有點激動。。。
從此以后,我便迷上了這個游戲,只要一有空我就會掏出游戲機擼上幾局。然而。。。一直玩這個游戲,慢慢我也產生厭倦了,我想換個游戲玩,可是這個游戲機里就一個游戲,怎么辦呢。。此時,商店里還有很多裝了不同游戲類型的游戲機,我的第一反應就是再去買一個,可是一想,再買一個又得花錢,當時的價格對于我來說簡直是天價,畢竟有個5毛一快的,那時候在小伙伴中都可以算個“有錢人”。。。再說即使買了,要是一個兩個還好,要是好幾個放家里,也是礙事。這時,我突然想到鄰居一位大哥哥平時挺喜歡搗鼓這些電子器件的,就想著能不能讓他幫我把游戲改改,果然,他說可以,不過操作上還是比較麻煩的需要把機子拆開,然后把游戲代碼重新寫到設備上,最后還得組裝起來。雖然這花了幾天時間,但好歹我又有新游戲可以玩了。然而再好玩的游戲也會有玩膩的一天,一段時間后,我又想玩新的游戲了,我第一反應就是去找哪位大哥哥,可是轉念一想,改個游戲沒想象中的那么簡單,每次都需要把機子拆了,重新寫程序,再重新組裝,想到這些,我又打消了念頭。就這樣,我把游戲機扔在了一旁,專心看起了我的動畫片。直到有一天,我看見小伙伴中有人在玩這個:
正面
我們當時管這叫“gameboy”,也是一種手持游戲機,不過要比之前的那種高端,他的背部有個插槽,可以插入不同的游戲卡。
?
背面
臥槽!這不正是我需要的嗎,想要玩什么游戲,就插入什么卡就行了,簡直不要太爽好吧。。
好了,既然出現了個新家伙,我們來看看用代碼怎么描述這個它,我們剛才看到比起之前的游戲機它的背部多了個插槽或者叫做接口,用于插入游戲卡。廠家在制作游戲卡時,也會準從一套標準,最主要的標準就是游戲卡上的接口類型要和游戲機上的一致,比如游戲機插槽有幾個管腳,那么游戲卡的接口處就得做幾個管腳,總不能在這游戲機上插入小霸王的卡把。。除了游戲卡的接口處要和游戲機上的插槽一致外,游戲卡中最重要的就是要有游戲啦,不然要這卡干嘛。這樣,只要制作游戲卡的時候都遵循這個標準,那么含有不同游戲的卡就都能插入到游戲機上。好了我們來看下代碼:
/*** 游戲卡制作的標準,插槽接口處類型為GameBoyKard*/ public interface GameBoyKard { // 卡里裝的游戲,生產時才裝入void game(); }同理,生產GameBoy也有一套標準:
public abstract class GameBoyPlayerModel {// 游戲機上裝有一個類型為GameBoyKard的插槽,表示只允許GameBoy的卡插入private GameBoyKard mGameKard; // 游戲機的外觀,有生產過時決定public abstract void display();// 用于插入游戲卡public void setGameKard(GameBoyKard gameKard){this.mGameKard = gameKard;}// 開始游戲按鈕public void startGame(){mGameKard.game();} }我們可以看到,比起之前的那個游戲機,這個gameboy游戲機已經沒有內置的游戲了,而是多了一個插槽,用于插入游戲卡。有了這套標準,我們生產一臺gameboy游戲機就方便多了,比如我們也想生產一臺紅色的:
public class RedGameBoyPlayer extends GameBoyPlayerModel{@Overridepublic void display() {System.out.print("這是一臺紅色的GameBoy");} }也是很簡單,基于之前定義的標準,我們只要生產時給定顏色就可以了。
這樣,我們的游戲機就有了,不過里面可沒裝任何游戲,我們還需要一張游戲卡:
public class TetrisGameCard implements GameBoyKard {@Overridepublic void game() {System.out.print("正在俄羅斯方塊游戲中...");} }可以看到我們定義了一張裝有俄羅斯方塊的游戲卡,當然這張卡的設計標準都是遵循GameBoyKard的標準。
好了,游戲機和游戲卡都已經就緒,趕緊來試下吧:
public class TestClient {public static void main(String[] args){ // 生產一臺紅色gameboyRedGameBoyPlayer redGameBoyPlayer = new RedGameBoyPlayer(); // 生產一張俄羅斯方塊游戲卡TetrisGameCard tetrisGameCard = new TetrisGameCard(); // 向游戲機中插入游戲卡redGameBoyPlayer.setGameKard(tetrisGameCard); // 開始游戲redGameBoyPlayer.startGame();} }代碼執行結果: --------------------------------------------------------------------------------------------------------------------- 正在俄羅斯方塊游戲中... ---------------------------------------------------------------------------------------------------------------------怎么樣,游戲跑起來,還不錯把,可能你想玩點其他游戲,沒關系,我們只用換張卡就行了,比如有一張賽車的游戲卡:
public class CarGameCard implements GameBoyKard {@Overridepublic void game() {System.out.print("正在賽車游戲中...");} }只要把這張卡插入游戲機中,就可以更換游戲了:
// 生產一張賽車游戲卡CarGameCard carGameCard = new CarGameCard(); // 向游戲機中插入游戲卡redGameBoyPlayer.setGameKard(carGameCard); // 開始游戲redGameBoyPlayer.startGame();代碼執行結果: --------------------------------------------------------------------------------------------------------------------- 正在賽車游戲中... ---------------------------------------------------------------------------------------------------------------------怎么樣,是不是感覺gameboy游戲機的這種設計比之前要方便很多。其實這種設計方法正是運用了我們今天的主角--策略模式。好了來看下它的定義:
策略模式 -- 定義算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化獨立于使用算法的客戶。
定義可能有點抽象,不過想想我們這個游戲機的例子,這里的算法族可以理解為某個游戲,我們用游戲卡封裝游戲,這樣游戲就從游戲機中獨立出來,并且不同的游戲卡可以互相切換,這樣你再看下定義是不是就好理解多了呢?
那么這種設計模式對我們代碼來講有哪些優勢呢?在上文一開始介紹的游戲機,如果我們想換個游戲玩,有兩種方式,第一種,就是再去買個游戲機,但是為了換個游戲,我又多了個游戲機,,我們可以看到游戲機的類都是GamePlayerModel這個抽象類的子類,采用這種方式,必定會造成大量的子類以及重復代碼。第二種方式就是直接改寫游戲機中的游戲,這種方式也是不推薦的。如果直接在代碼中修改,一來比較麻煩,再者,這樣頻繁修改很容易會影響其他功能模塊,對項目的維護性和擴展性大打折扣。相反,我們在看看使用了策略模式的游戲機,我們不再需要定義大量不同的游戲機子類,我們要改變的是游戲,只用創建不同游戲卡類就行了,而且不同的卡之間可以互相切換,對原來的功能模塊也不會產生任何影響。
另外在策略模式中我們也可以看出幾條設計原則,什么是設計原則呢?我們都知道,每種編程語言都有語法,如果你在編程時不遵守語法,那么編譯器就會報錯。就好比法律,如果你不守法,那么就會得到制裁。除了守法外,我們都是講道德的,這是要高于法律的。這里的設計原則就像是我們的品德,當然你可以不遵守這些設計原則,只要編譯器不報錯就好了,不過我相信大家都是講道德的人,為了不讓我們的代碼去坑別人,我們還是來看看設計原則吧。在策略模式中,包含了這幾條設計原則:
1.在代碼中把那些可能變化的地方分離開來,別讓它和不變的代碼混在一起。
2.針對接口編程,而不是針對實現編程。
3.多用組合,少用繼承。
相信從字面上也是很好理解,我們再結合上面的例子簡單講下。第一條,在最開始的游戲機類中,有兩個方法,游戲和外觀,一般游戲機生產出來外觀就不會有變化了,而我們想改變的是里面的游戲,所以在gameboy游戲機中,游戲從游戲機中分離了出來。第二,在之前的游戲機中,游戲是直接實現在游戲機類中,而gameboy則是用到游戲的接口。第三條,顧名思義,每個gameboy游戲機都能和不同的游戲卡任意組合,當然這個游戲卡,要實現相應的接口。而之前的游戲機類都是繼承于父類,里面的游戲也就寫死了。
我有一個qq群:671900195,經常會分享一些Java技術相關的干貨;如果你喜歡我的分享記得加群哦!!!
好了,這篇文章到這也就差不多了,相信你已經很好的掌握了策略模式以及其中體現的幾點設計原則。如果哪天突然忘了什么是策略模式,就想想小時候玩的游戲機吧!
?
總結
以上是生活随笔為你收集整理的设计模式- 策略模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java面试题系列之Java基础类库(一
- 下一篇: 面试中的设计模式