【設計模式系列】--策略模式

什麼是策略模式

在前面的博文中,小編主要向小夥伴介紹了組合模式,今天這篇博文,我們繼續來學習設計模式的相關知識,今天和小夥伴們見面的是策略模式,策略模式英文名字叫Strategy,策略模式屬於行爲模式的一種,她對一系列的算法加以封裝,爲所有算法定義一個抽象的算法接口,並通過繼承該抽象算法接口對所有的算法加以封裝和實現,具體的算法選擇交由客戶端決定,策略模式主要用來平滑的處理算法的切換。

策略模式結構圖

我們來看一下策略的結構圖,如下所示:


  對上述結構圖進行簡單的解釋說明:

        a、將所有的算法都抽象成了Strategy,可以將算法分離出來並且進行更換。
        b、Context 中含有對Strategy的引用。
        c、通過contextInterface(),進行對算法的使用。

         從上面的結構圖中,可以看出這些算法完成的都是相同的工作,只是實現不同,它可以以相同的方式調用所有的算法,減少各種算法類與使用算法類之間的耦合。換句話說,策略模式並不將算法固定在具體的某個類中,而是將算法獨立出來,可根據需要替換算法。例如:Context中含有對 Straategy的引用。這裏還用到了依賴倒轉和里斯代換原則,即Context依賴於抽象,而沒有依賴具體的子類,並且,子類可以替換父類。

策略模式簡單應用demo

接着,我們通過一個簡單的demo來了解一下策略模式是如何在實際中加以應用的,新建java項目Strategy,新建類MainClass,新建接口Strategy,編寫接口裏面的代碼部分,如下所示:

public interface Strategy {
	//加密
	public void encrypt();
	
新建類MD5Strategy,實現接口Strategy,編寫相關代碼,如下所示:

public class MD5Strategy implements Strategy {

	@Override
	public void encrypt() {
		System.out.println("執行MD5加密");

	}

}
新建類MDSStrategy,實現接口Strategy,編寫相關代碼,如下所示:

public class MDSStrategy implements Strategy {

	@Override
	public void encrypt() {
		System.out.println("執行MDS加密");

	}

}
如果我們不使用策略模式,我們會在MainClass裏面如何編寫代碼呢?如下所示:

public class MainClass {
	public static void main(String[] args){
		Strategy stra =  new MD5Strategy();
		stra.encrypt();
	}
}
運行如下所示:



如果要執行MDSS的方法,我們可以對MainClass中的代碼部分進行修改,如下所示:

public class MainClass {
	public static void main(String[] args){
		Strategy stra =  new MDSStrategy();
		stra.encrypt();
	}
}
運行效果如下所示:

通過這種方式,可以實現動態的轉變,我們只需要在客戶端進行改變即可,但是這個不符合策略模式,通過結構圖,我們可以看到有一個Context,可以理解成是一個工廠,創建Context類,並編寫相關代碼,如下所示:

public class Context {
	private Strategy strategy;
	public Context(Strategy strategy){
		this.strategy = strategy;
	}
	
	public void encrypt(){
		this.strategy.encrypt();
	}

}
編寫客戶端的代碼,如下所示:

public class MainClass {
	public static void main(String[] args){
//		Strategy stra =  new MDSStrategy();
//		stra.encrypt();
		
		Context context = new Context(new MD5Strategy());
		context.encrypt();
	}
}
運行如下所示:



執行MDSS,修改客戶端代碼如下所示:

public class MainClass {
	public static void main(String[] args){
//		Strategy stra =  new MDSStrategy();
//		stra.encrypt();
		
		Context context = new Context(new MDSStrategy());
		context.encrypt();
	}
}
運行如下所示:


通過這兩種方式的實現,經過對比我們可以發現,我們直接通過Context進行調用,我們可以把Strategy看成是一個抽象的接口,我們再來舉一個簡單的例子,幫助我們進一步加深對策略模式的理解,新建包Strategy,新建類MainClass,新建接口Strategy,編寫相關代碼如下所示:

package Strategy;

public interface Strategy {
	public double cost(double num);
}
新建類StrategyA實現Strategy,編寫相關代碼,如下所示:

package Strategy;

public class StrategyA implements Strategy {

	@Override
	public double cost(double num) {
		return num*0.8;
	}

}
新建類Context,編寫相關代碼,如下所示:

package Strategy;

public class Context {
	private Strategy strategy;
	
	public Context (Strategy strategy){
		this.strategy=strategy;
	}
	
	public double cost(double num){
		return this.strategy.cost(num);
	}

}
新建MainClass,編寫相關代碼,如下所示:

package Strategy;

public class MainClass {
	public static void main(String[] args) {
		double num = 200;
		Context context = new Context(new StrategyA());
		double newNum = context.cost(num);
		System.out.println("實際付款"+newNum+"元");
	}

}
運行如下所示:


這個時候,商家改變策略,不打八折了,這個時候改成滿200返50,我們該如何實現呢?新建類StrategyB,實現Strategy,編寫相關代碼,如下所示:

package Strategy;

public class StrategyB implements Strategy {

	@Override
	public double cost(double num) {
		if(num >= 200){
			return num-50;
		}
		return num;
	}

}
編寫MainClass中的代碼部分,如下所示:

package Strategy;

public class MainClass {
	public static void main(String[] args) {
		double num = 200;
		Context context = new Context(new StrategyB());
		double newNum = context.cost(num);
		System.out.println("實際付款"+newNum+"元");
	}

}
運行如下所示:


這樣,我們直接實現接口,寫一個方法就可以了,接着,我們來看一下策略模式的優缺點:

優點:

a、策略模式提供了管理相關的算法族的辦法,策略類的等級結構定義了一個算法或行爲族,恰當使用繼承可以公共的代碼移到父類裏面,從而避免重複的代碼。

b、策略模式提供了可以替換繼承關係的辦法,繼承可以處理多種算法和行爲,如果不使用策略模式,那麼使用算法或行爲的環境類就可能會有一些子類,每一個子類提供一個不同的算法和行爲,但是,這樣一來算法或行爲的使用者就和算法或行爲本身混在一起,決定使用哪一種算法或採取哪一種行爲的邏輯就和算法或行爲的邏輯混合在一起,從而不可能再單獨演化,繼承使得動態改變算法或行爲變得不可能。

c、使用策略模式可以避免使用多重條件轉移語句,多重轉移語句不易維護,他把採用哪一種算法或採取哪一種行爲的邏輯與算法或行爲的邏輯混合在一起,統統列在一個多重轉移語句裏面,比使用繼承的辦法還要原始和落後。

缺點:

a、客戶端必須知道所有的策略類,並執行決定使用哪一個策略類,這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類,換言之,策略模式只適用於客戶端知道所有的算法或行爲的情況。
b、策略模式造成很多的策略類,有時候可以通過把依賴於環境的狀態保存到客戶端裏面,而將策略類設計成可共享的,這樣策略類實例可以被不同客戶端使用,換言之,可以使用享元模式來減少對象的數量。

小編寄語:該博文小編主要簡單的介紹了策略模式,分別從什麼是策略模式、策略模式的結構圖、策略模式簡單應用demo、策略模式的優缺點四個方面對策略模式進行了簡單的介紹,策略模式是一個比較容易理解和使用的設計模式,策略模式是對算法的封裝,它把算法的責任和算法本身分割開,委派給不同的對象管理。策略模式通常把一個系列的算法封裝到一系列的策略類裏面,作爲一個抽象策略類的子類。用一句話來說,就是“準備一組算法,並將每一個算法封裝起來,使得它們可以互換”。在策略模式中,應當由客戶端自己決定在什麼情況下使用什麼具體策略角色。策略模式僅僅封裝算法,提供新算法插入到已有系統中,以及老算法從系統中“退休”的方便,策略模式並不決定在何時使用何種算法,算法的選擇由客戶端來決定。這在一定程度上提高了系統的靈活性,但是客戶端需要理解所有具體策略類之間的區別,以便選擇合適的算法,這也是策略模式的缺點之一,在一定程度上增加了客戶端的使用難度。


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