策略模式的理解
最初的設計
假設有一家公司——帕特蘭,該公司研製了一款生產設備,可以生產出多功能高科技產品uranus G1(第一代)。G1產品具有A、B兩項功能,深受全球用戶喜愛,掀起一股搶購浪潮,產品開始大規模銷往世界各地,中國、意大利、法國、德國等很多國家。
但是很快,各國用戶開始反映,雖然A、B功能非常實用,但產品外觀有些單一,銷往各國的產品長得都一樣,如果每款產品可以體現各國自己的風情文化,豈不更好?
帕特蘭公司立刻採取行動,針對各國風情設計了不同的外觀,如銷往中國的加入了中國風,銷往法國的則加入了浪漫的元素。於是,生產線現在是這樣:
圖1
加入新的功能
隨着用戶的需求不斷增加,帕特蘭公司決定給G1系列產品加入功能C。因爲生產線採用了OO的思想,只需要在基類中加入功能C(如圖2所示),那麼所有繼承該基類的子類(即圖1中標號爲2、3、4的分支線)生產出的G1產品,自然就具有了功能C,設計者們這下嚐到了OO設計與繼承的甜頭。
圖2
產品又升級
現在又需要加入D功能。帕特蘭公司在這方面已經駕輕就熟,只需要像加入C功能一樣在基類中加入D就好了,而且產品開始銷往更多的國家。
圖3
可是這次沒有像之前那麼順利,由於各國地區文化差異,法國和美國某些地區的用戶,美國加州的用戶不喜歡D功能,法國巴黎的用戶覺得D功能稍微修改一下,變成D1功能比較合口味。帕特蘭公司的設計者採用了這樣的方式解決這個問題:生產線再加入一級過濾層,
對個別地區的產品進行修整,其餘大部分產品保持原樣即可。
圖4
雖然解決了這個問題,但是帕特蘭公司的設計者開始發現設計中存在一個非常大的問題,那就是以後還會加入E功能,還會銷往更多的國家和地區,如果E功能在更多地區出現D的類似情況,可就不妙了,比如,日本東京的用戶覺得E改成E1,而中國杭州的用戶偏偏喜歡E,意大利羅馬的用戶覺得改成E2更舒服。你想象一下,隨着功能的不斷加入,銷售地區更多,地區文化差異大,在圖中的2級分支處,讓一個人來維護,那工作量將是多麼的驚人!
策略模式怎麼做
帕特蘭公司的設計人員開始研究策略模式,發現原來有一種更好的設計方式,可以將剛纔那個噩夢般的維護工作瞬間變得容易了。
設計人員做了以下幾件事情:
將世界通用的功能A、B、C保留在基類中實現,因爲這些功能滿足所有地區,幾乎不會變動;
將容易隨着地區不同而變動的D,E功能的實現從基類中抽離出來,只留了兩個位置d、e,表示這兩個功能,主生產線暫時不實現;
對位置d、e規定了接口規範,比如d位置有三個菱形插孔,e位置有兩個圓形插孔,採用該接口規範設計的零件可以安插在相應的位置,即插即用
成立一條獨立的生產線line2(原來的生產線統稱爲line1),專門負責生產實現D、D1、空D、E、E1、空E等功能的零件,並採用3中規定的接口標準。
安排一個人peter,專門負責從line1中取出G1半成品(即只有ABC功能,D和E只留了位置),從line2取出生產出的D、E零件,將零件安插在相應的位置上;
現在情況是什麼呢?
以後再有哪個地區突然說不喜歡D或E,或者要改成D2,E2,亦或是D3、E3也沒關係,只需要在line2中添加一個這樣的零件,而line1仍舊像以前一樣保留d、e位置,一點修改都不用做,在打算生產具有D2、E2、D3、E3功能的產品時,peter自然會取出新添加的零件,安插在預留的位置,對於peter而言,拿的動作和安插的動作也是完全相同,只是拿了不同的零件而已。
這就是策略模式。
再來看概念
現在來看一下策略模式的抽象概念,如果你看懂了前面的例子,那麼請原諒我到這裏才介紹概念。
策略模式的概念:將一系列行爲(動作、算法)封裝起來,功能類似的行爲都實現一個統一的接口,使這些行爲的變化修改獨立於行爲的使用者。
這裏的行爲對應的就是line2生產的具有功能D2、D3、E2、E3的零件;
統一的接口就是預留的位置d、e所規定的一系列特徵,如三插孔、菱形等;
行爲的使用者即line1生產出的半成品;
預留位置,其實就是在基類中加入一個行爲對象,以接口類型來引用(即使用組合,針對接口編程),委託給變量來實現具體功能;
安插零件的動作則對應基類的set方法,來設置實際的行爲對象;
Peter扮演的就是基類和行爲類的用戶(可以理解成寫main函數的程序員),針對不同的地區調用set方法設置不同的行爲對象。
設計原則
多用組合少用繼承
針對接口編程,而非針對實現編程
分離並封裝易於變化的行爲,獨立於固定不變的部分