Java 大白話講解設計模式之 -- 策略模式

聲明:原創作品,轉載請註明出處https://www.jianshu.com/p/4d53aa2adb22

在開始說設計模式之前,讓我們先聊點別的東西,相信每個人都有自己難忘的童年時光,在那時有很多有趣好玩的事物陪伴着我們。我記得小時候,很喜歡看一部動畫片--《四驅兄弟》,,,好吧暴露年紀了。。受動畫片的影響,還經常和小夥伴們一起買四驅玩具車玩。除了玩具車外,我還喜歡玩遊戲機來打發時間,當然不是你想的那種遊戲主機什麼的,而是這種:


。。可能現在有些小夥伴不認識這傢伙了,這其實就是一個手持的小型遊戲機,裏面內置了幾種遊戲,我能夠想起的幾種遊戲一個是比較經典的俄羅斯方塊,還有個是很簡單的賽車遊戲,就是在遊戲中不斷躲避障礙物,並且速度還會不斷加快。種類還是比較少的。好了言歸正傳,一般工廠生產產品時,都需要一個模具,或者說一套標準,在生產具體的產品時,都得照着這個標準做。好了,那麼生產這個遊戲機的標準是怎樣的呢,我們可以定義一個類來描述這個標準:

/**
 * 工廠中製作遊戲機的一個模型標準(類似於模具)
 */
public abstract class GamePlayerModel {
//    每個遊戲機都內置一款遊戲,具體遊戲類型在生產具體的遊戲機時裝入
    abstract void game();
//    遊戲機外觀,具體在生產時決定
    abstract void display();
//    點擊遊戲機上的開始遊戲按鈕進入遊戲
    public void startGame(){
        game();
    }
}


可以看到,在這個遊戲機模具中,內置了一款遊戲(這裏假設每個遊戲機中只有一款遊戲),當然開始什麼也沒裝,只有在生產具體類型的遊戲機時纔會裝入相應的遊戲,還有個開始遊戲的方法,當點擊開始遊戲就會調用內置的遊戲。裏面還有個display方法,表示遊戲機的外觀,具體是什麼顏色,也只有在生產時才能決定。當然這裏的模型我們是經過簡化的,事實上要複雜很多。

好了有了這個遊戲機模型,我們生產一個遊戲機就很方便了,比如我們需要生產一個紅色的內置俄羅斯方塊遊戲的遊戲機,我們定義一個類來描述:

public class RedTetrisPlayer extends GamePlayerModel{
    
    @Override
    void game() {
        System.out.print("正在俄羅斯方塊遊戲中...");
    }

    @Override
    void 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{
    @Override
    public void display() {
        System.out.print("這是一臺紅色的GameBoy");
    }
}

也是很簡單,基於之前定義的標準,我們只要生產時給定顏色就可以了。

這樣,我們的遊戲機就有了,不過裏面可沒裝任何遊戲,我們還需要一張遊戲卡:

public class TetrisGameCard implements GameBoyKard {
    @Override
    public void game() {
        System.out.print("正在俄羅斯方塊遊戲中...");
    }
}

可以看到我們定義了一張裝有俄羅斯方塊的遊戲卡,當然這張卡的設計標準都是遵循GameBoyKard的標準。

好了,遊戲機和遊戲卡都已經就緒,趕緊來試下吧:

public class TestClient {

    public static void main(String[] args){
//       生產一臺紅色gameboy
        RedGameBoyPlayer redGameBoyPlayer = new RedGameBoyPlayer();
//        生產一張俄羅斯方塊遊戲卡
        TetrisGameCard tetrisGameCard = new TetrisGameCard();
//        向遊戲機中插入遊戲卡
        redGameBoyPlayer.setGameKard(tetrisGameCard);
//        開始遊戲
        redGameBoyPlayer.startGame();
    }
}


代碼執行結果:
---------------------------------------------------------------------------------------------------------------------
正在俄羅斯方塊遊戲中...
---------------------------------------------------------------------------------------------------------------------

怎麼樣,遊戲跑起來,還不錯把,可能你想玩點其他遊戲,沒關係,我們只用換張卡就行了,比如有一張賽車的遊戲卡:

public class CarGameCard implements GameBoyKard {
    @Override
    public void game() {
        System.out.print("正在賽車遊戲中...");
    }
}

只要把這張卡插入遊戲機中,就可以更換遊戲了:

//        生產一張賽車遊戲卡
        CarGameCard carGameCard = new CarGameCard();
//        向遊戲機中插入遊戲卡
        redGameBoyPlayer.setGameKard(carGameCard);
//        開始遊戲
        redGameBoyPlayer.startGame();


代碼執行結果:
---------------------------------------------------------------------------------------------------------------------
正在賽車遊戲中...
---------------------------------------------------------------------------------------------------------------------

怎麼樣,是不是感覺gameboy遊戲機的這種設計比之前要方便很多。其實這種設計方法正是運用了我們今天的主角--策略模式。好了來看下它的定義:

策略模式 -- 定義算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化獨立於使用算法的客戶。

定義可能有點抽象,不過想想我們這個遊戲機的例子,這裏的算法族可以理解爲某個遊戲,我們用遊戲卡封裝遊戲,這樣遊戲就從遊戲機中獨立出來,並且不同的遊戲卡可以互相切換,這樣你再看下定義是不是就好理解多了呢?

那麼這種設計模式對我們代碼來講有哪些優勢呢?在上文一開始介紹的遊戲機,如果我們想換個遊戲玩,有兩種方式,第一種,就是再去買個遊戲機,但是爲了換個遊戲,我又多了個遊戲機,,我們可以看到遊戲機的類都是GamePlayerModel這個抽象類的子類,採用這種方式,必定會造成大量的子類以及重複代碼。第二種方式就是直接改寫遊戲機中的遊戲,這種方式也是不推薦的。如果直接在代碼中修改,一來比較麻煩,再者,這樣頻繁修改很容易會影響其他功能模塊,對項目的維護性和擴展性大打折扣。相反,我們在看看使用了策略模式的遊戲機,我們不再需要定義大量不同的遊戲機子類,我們要改變的是遊戲,只用創建不同遊戲卡類就行了,而且不同的卡之間可以互相切換,對原來的功能模塊也不會產生任何影響。

另外在策略模式中我們也可以看出幾條設計原則,什麼是設計原則呢?我們都知道,每種編程語言都有語法,如果你在編程時不遵守語法,那麼編譯器就會報錯。就好比法律,如果你不守法,那麼就會得到制裁。除了守法外,我們都是講道德的,這是要高於法律的。這裏的設計原則就像是我們的品德,當然你可以不遵守這些設計原則,只要編譯器不報錯就好了,不過我相信大家都是講道德的人,爲了不讓我們的代碼去坑別人,我們還是來看看設計原則吧。在策略模式中,包含了這幾條設計原則:

1.在代碼中把那些可能變化的地方分離開來,別讓它和不變的代碼混在一起。
2.針對接口編程,而不是針對實現編程。
3.多用組合,少用繼承。

相信從字面上也是很好理解,我們再結合上面的例子簡單講下。第一條,在最開始的遊戲機類中,有兩個方法,遊戲和外觀,一般遊戲機生產出來外觀就不會有變化了,而我們想改變的是裏面的遊戲,所以在gameboy遊戲機中,遊戲從遊戲機中分離了出來。第二,在之前的遊戲機中,遊戲是直接實現在遊戲機類中,而gameboy則是用到遊戲的接口。第三條,顧名思義,每個gameboy遊戲機都能和不同的遊戲卡任意組合,當然這個遊戲卡,要實現相應的接口。而之前的遊戲機類都是繼承於父類,裏面的遊戲也就寫死了。

好了,這篇文章到這也就差不多了,相信你已經很好的掌握了策略模式以及其中體現的幾點設計原則。如果哪天突然忘了什麼是策略模式,就想想小時候玩的遊戲機吧!

設計模式持續更新中。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章