前言:
最近在寫項目的時候,深感設計模式的重要性。一個人的代碼寫的好不好,別人看的舒不舒服,和會不會設計模式緊密關聯的。之前看過四人幫的設計模式。但當時僅限於看,包括現在也僅限於看。有的時候項目中,你都不知道有沒有運用到了設計模式。也許用到了單例模式,但你並不知道如何用的,不知不覺就用到了。
《武林外傳》老白曾經說過這樣一句話。高手就是手里無刀,心中也無刀。類似於設計模式,你不知不覺中已經融進你的代碼中了,但你並不知已經運用了。當然我沒有達到這個境界,可能五年,十年,或者更久,誰也說不准呢。
這次正好趁這個項目,把用到的涉及模式總結一下,策略模式和模板方法模式。
1:設計模式分類
總體來說設計模式分為三大類:
創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
我們這次講的都屬於行為型模式。這類模式負責對象間的高效溝通和職責委派。注意理解下對象間,責任委派。
2:策略模式
策略模式是一種行為設計模式, 它能讓你定義一系列算法, 並將每種算法分別放入獨立的類中, 以使算法的對象能夠相互替換。
在我的項目中有這么一個場景,大家也可以想象一個。用戶購買商品支付的時候,可能會使用多種不同的優惠券。比如說,貼息,滿減,隨機立減等等
這幾種返回給前端的金額,文案,以及個個方法都有比較大的差異。我們可以理解為三種不同的算法,選擇哪種策略,完全由用戶有哪張優惠券所決定的。
因此很簡單的,我們可以使用策略模式。
1: 我們首先先定義一個接口
1 @Service 2 public interface CouponStrategy { 3 4 void execute(Coupon coupon); 5 6 }
2:定義不同的實現類
1 class CouponStrategyA implements CouponStrategy { 2 3 @Override 4 public void execute(Coupon coupon) { 5 // 第一種具體算法 6 } 7 8 } 9 10 class CouponStrategyB implements CouponStrategy { 11 12 @Override 13 public void execute(Coupon coupon) { 14 // 第二種具體算法 15 } 16 17 }
3:我們可以根據coupon選擇不同的算法。這里我們可以采用工廠模式
1 @Service 2 public class CouponStrategyFactory { 3 4 5 private Map<String, CouponStrategy> serviceMap = new HashMap<>(); 6 7 8 public CouponStrategy getService(CouponInfo couponInfo) { 9 10 CouponStrategy couponStrategy = serviceMap.getOrDefault(coupon.getCouponType(), couponDefault); 11 12 return couponStrategy; 13 } 14 15 }
最后,這種算法看起來是非常的干凈整潔舒服的。比如之前很多type=1,則算法A。type=2則算法B。代碼雖然實現,但看起來很難受。
並且策略模式讓你能將不同行為抽取到一個獨立類層次結構中, 並將原始類組合成同一個, 從而減少重復代碼。比如我可以把A,B,C算法重復的都抽象到interface接口中,代碼最重要一點就是避免寫重復性的代碼。
3:模板模式
模板方法模式是一種行為設計模式, 它在超類中定義了一個算法的框架, 允許子類在不修改結構的情況下重寫算法的特定步驟。
比如我們JDK經典的ArrayList,用到的就是模板模式,我們看一下他的類圖如下:
這幅圖真的特別的經典,可以說是學習模板方法最好的實踐了。
ArrayList繼承了AbstractList並且實現了多種的接口。ArrayList只實現了自己特定的算法,其余比較通用的算法全部由AbstractList實現。
比如addAll方法, 它位於absract接口。它定義了一系列的算法,比如首先check,在for循環add等等。
但是具體怎么add他並沒有實現,而是交由子類去具體實現。
1 public boolean addAll(int index, Collection<? extends E> c) { 2 rangeCheckForAdd(index); 3 boolean modified = false; 4 for (E e : c) { 5 add(index++, e); 6 modified = true; 7 } 8 return modified; 9 }
比如ArrayList的實現
1 public void add(int index, E element) { 2 rangeCheckForAdd(index); 3 4 ensureCapacityInternal(size + 1); // Increments modCount!! 5 System.arraycopy(elementData, index, elementData, index + 1, 6 size - index); 7 elementData[index] = element; 8 size++; 9 }
又比如LinkedList
1 public void add(int index, E element) { 2 checkPositionIndex(index); 3 4 if (index == size) 5 linkLast(element); 6 else 7 linkBefore(element, node(index)); 8 }
類似於子類可以通過鈎子操作可以控制父類的行為,是不是很神奇。
最后,當你只希望客戶端擴展某個特定算法步驟, 而不是整個算法或其結構時, 可使用模板方法模式。 模板方法將整個算法轉換為一系列獨立的步驟, 以便子類能對其進行擴展, 同時還可讓超類中所定義的結構保持完整。
4:策略模式和模板模式同與異
這兩種模式非常的相像,一不留神可以分不清楚用那種模式了。當然這就是開頭所說的,心中有刀,手里已無刀,你不知不覺中已經融進你的代碼中了,但你並不知已經運用了。這其實就是最棒的結果了,但對於咱們初學者,剛開始弄清楚還是有必要的。
相同點:
1: 毋庸置疑都可以減少代碼的重復,將重復代碼抽象到父類即可。
2: 可以很容易的切換算法,根據前端傳來的參數,具體算法何種算法,何種模式。
不同點:
1:模板模式基於繼承機制: 它允許你通過擴展子類中的部分內容來改變部分算法。
2:策略模式基於組合機制: 你可以通過對相應行為提供不同的策略來改變對象的部分行為。 模板方法在類層次上運作, 因此它是靜態的。 策略在對象層次上運作, 因此允許在運行時切換行為。
3:模板更加看重是算法的流程,全部已經規定好了,子類可以修改部分流程算法
4:策略模式是將整個算法全部重寫,不是部分,而是整體。
最后祝大家都能寫出漂亮,驚艷,眼前一亮的代碼。最終做到,手里無刀,心中也無。