序言
最近在看Head First 設計模式這本書,看了一點,第一感覺是簡單,通俗易懂,層序漸進,基本上稍微耐心一點都看得懂,那麼這本書這麼多優點,我寫博文是為了什麼呢,方便自己以後觀看嗎?那我還不如看一遍書呢,既然書寫的那麼好,寫給別人看?那還不如推薦別人直接去看書呢。寫著系列的博文這也沒用,那也沒用,那我的出發點是什麼呢? 好。我腦袋中的構思是先講解一下每個模式的基本概念,也就是讓你們先知道講的這個模式的大概意思(儘量跟書上一樣簡單,就相當於我怎麼想的告訴你們,你們可以用來借鑑,如果有更好的講解方式,可能一起討論),然後通過找一些例項,來看看這個模式在哪些地方用到了。加深我們的映像,讓我們學習設計模式的時候,也能學點別的東西。 這就是我寫這一系列博文的目的。
--WH
策略模式
一、準備知識
多型:父類物件引用子類例項物件,A extends B,A a = new B(); A、B中都有方法run,a.run();此時就是呼叫B中的run方法。這就是執行時多型,
為什麼叫執行時多型呢?因為在編譯的時候,不知道真正的a到底是什麼,只知道a是A,在執行時才發現a是B的例項,呼叫的也就是B中的方法,
這樣做有什麼好處?靈活性、簡化性、這種只能通過自己多敲程式碼才能感覺得到使用多型的好處。。。
行為組合:通過學習策略模式你就知道了什麼是行為組合
二、什麼是策略模式?
在Head First設計模式的書中,用的鴨子的各種行為的例子來說明,看的我頭暈眼花,各種鴨子,橡皮鴨都出來了,而且是一步步帶領你進入到他所要說的那種思想上去。我感覺對於我這種不喜歡囉嗦麻煩的人來說,是個噩夢,直接看了下面這個圖,就理解了什麼是策略模式
一個遊戲中有很多角色,有國王、王后、騎士、妖怪等人物,並且每個人物作戰的方式也不同,怎麼實現呢?
1、普通方法實現。
看起來不錯啊,哈哈,應有盡有,但是缺點很多,
1、如果king的戰鬥方式需要改變呢,變成用槍了,那麼我們只好在king類中增加一個GunBehavior方法,然後將fight中改為呼叫GunBehavior
2、遊戲不止三個騎士,那就來100個騎士,都使用弓箭,但是後面改革了,騎士改為用斧頭了,本來妖怪類中就已經實現了斧頭的方法,但沒辦法,我們還有自己在在騎士中實現一遍
3、這樣一來,可擴充套件性和可複用性都非常差。每個人物中的方法都可能有重複。
2、通過策略者模式怎麼實現的呢?看下圖。
1、變化的部分:每個人物使用的戰鬥行為不一樣。所以將戰鬥的行為都提取出來獨立當成一個類
2、將戰鬥行為抽取出一個介面來,為的就是使用介面程式設計的方式。
3、在Character中申明一個WeaponBehavior變數,也就是為了介面程式設計後使用多型更方便。
通過上面三步的改造,現在king使用什麼戰鬥方式,只需要new出來就行了,如果要使用槍,只需要在建立一個GunBehavior的類,然後讓king使用
如果騎士,他們也想用斧頭,那麼就把騎士中改一行程式碼,改為用斧頭類就好了。
其實策略者模式最關鍵的就是將行為都提取出來封裝成獨立類,然後讓使用者想用什麼就new什麼。其他使用多型的地方只是設計原則所導致的。
畫圖有點失誤,沒有將weapon.useWeapon()呼叫。sorry。
策略者模式用到了哪些設計原則?
1、多用組合、少用繼承。這句話中的“組合”的意思就像上面的那些作戰行為都封裝成一個獨立的類,然後組合在一起。繼承在這個例子中並沒有體現出來。
2、針對介面程式設計、而不是針對實現程式設計。 這個其實就是為了用多型。
3、找出應用中可能需要變化的地方,把它們獨立出來,不要和那些不需要改變的程式碼混在一起。
策略模式的標準結構圖
三、JDK中使用的策略模式體現
1、Comparator介面
記得那個Comparetor這個介面嗎,這個就是使用了策略模式寫的。在做Comparator和Comparable的比較的時候就說過,實現Comparator是在外部實現compareTo方法,而實現Comparable介面是在內部實現compareTo方法,現在知道為什麼Comparator是在外部實現compareTo方法嗎,原因就是使用的是策略模式,每個功能/演算法類,都必須實現策略介面。然後再需要使用該類的時候,在將其new出來使用.光說沒有用,帶你看一個非常熟悉的類。String類中就用到了
首先看一下JDK中實現Comparator介面後擴充套件了一些什麼類
通過圖中可以看到實現該介面的類有很多,但是我們看到一個很熟悉的,java.lang.String下的一個類,說明這個CaseInsensitiveComparator在String中用到了。
開啟String的原始碼,檢視了一下,跟我們講解的一模一樣的形式
不管這個類的作用是什麼,反正我們是看到了熟悉的模式,
1、CaseInsensitiveComparator實現了Comparator介面
2、在String中Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
雖然這個是個常量,但是也沒什麼大的差別,跟我們自己寫的規範是一樣的。
2、ThreadPoolExecutor中的四種拒絕策略
在JDK中,這個也使用了策略模式,有興趣的可以去看看,這裡我就不帶著大家看了。
四、總結
其實我們平常的程式碼中,沒有那麼複雜,只需要將其中變化的部分給抽取出來,達到複用的目的就行了,這種策略模式一般都是在那種比較複雜的情況下,就將其按照上面標準的結構給實現下來。
策略模式的定義:
1、策略模式定義了演算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。
也個定義,通俗的講,也就是將那些使用的方法風別封裝成獨立的類,然後將這一類使用介面統一管理起來,讓需要使用這些方法的使用者能夠隨時呼叫他們。上面例子中的戰鬥行為就相當於定義中的演算法一詞。只是算了個說法而已。
缺點:
1、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道演算法或行為的情況。
2、由於策略模式把每個具體的策略實現都單獨封裝成為類,如果備選的策略很多的話,那麼這些類的數目就非常多了。