策略模式

策略模式(Strategy Pattern)是相對比較簡單的一種設計模式,是通過定義一組算法,並且將每個算法封裝到具有共同接口的獨立類中,從而使它們之間可以相互轉換,使算法在不影響客戶端的情況下發生變化。

策略模式體現了這樣兩個原則——封裝變化對接口編程而不是對實現編程設計模式的作者把策略模式定義如下:

Define a family of algorithms, encapsulate each one, and make them interchangeable. [The] Strategy [pattern] lets the algorithm vary independently from clients that use it.(策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立於使用它的客戶而變化。)

策略模式將整個軟件構建爲可互換部分的鬆耦合的集合,而不是單一的緊耦合系統。鬆耦合的軟件可擴展性更好,更易於維護且重用性好。


策略模式的UML


策略模式共涉及3種角色:
環境角色(Context):也叫上下文角色,用於屏蔽高層模塊對策略、算法的直接訪問,它持有一個Strategy類的引用。
抽象策略角色(Strategy):對策略、算法進行抽象,是每個具體策略角色必須實現的。
具體策略角色(Concrete Strategy):用於實現具體的策略、算法。

策略模式的應用
以商場促銷爲例,有的商品是打折促銷,有的商品是滿減,還有的是不促銷的,可以用策略模式進行優惠算法的封裝。


抽象策略角色:
public abstract class StrategyDiscount {

	private int num;
	private int price;
	
	public StrategyDiscount(int price, int num) {
		this.num = num;
		this.price = price;
	}
	
	public int getNum() {
		return num;
	}
	
	public int getPrice() {
		return price;
	}
	
	public abstract double getDiscount();
	
}

三個具體實現的策略角色,分別代表無促銷、滿減促銷、打折促銷
public class NoDiscountStrategy extends StrategyDiscount {


	public NoDiscountStrategy(int price,int num) {
		super(num, price);
	}
	
	@Override
	public double getDiscount() {
		return getPrice() * getNum();
	}
	
}

public class FixDiscountStrategy extends StrategyDiscount {

	public FixDiscountStrategy(int price, int num ) {
		super(num, price);
	}
	
	@Override
	public double getDiscount() {
		int sum = getNum() * getPrice();
		if(sum > 100 ) {  //滿100減20
			return sum-20;
		}else 
			return sum;
	}
	
}

public class PercentDisCountStrategy extends StrategyDiscount {

	public PercentDisCountStrategy(int price, int num) {
		super(num, price);
	}
	
	@Override
	public double getDiscount() {
		return 0.8 * getPrice() * getNum(); //打八折
	}
	
}

環境角色Context,屏蔽對具體策略角色的直接訪問
public class Context {

	private StrategyDiscount strategyDiscount;
	
	public Context(StrategyDiscount strategyDiscount) {
		this.strategyDiscount = strategyDiscount;
	}
	
	public double contextCalDisc() {
		return strategyDiscount.getDiscount();
	}
	
}

以上關於促銷案例的策略模式就已經完成,以下是客戶端調用的類
public class Client {

	public static void main(String[] args) {
		Context c1 = new Context(new NoDiscountStrategy(20, 6));
		System.out.println("該商品不促銷,購買總額: " + c1.contextCalDisc());
		
		Context c2 = new Context(new FixDiscountStrategy(20, 6));
		System.out.println("該商品參與滿減促銷,購買總額 : " + c2.contextCalDisc());
		
		Context c3 = new Context(new PercentDisCountStrategy(20, 6));
		System.out.println("該商品參與打八折促銷,購買總額 :" + c3.contextCalDisc());
		
	}
	
}


以上總結策略模式的優點:
1. 策略模式提供了管理相關算法族的辦法,可以把公用的特性移動到抽象策略角色中,以提高重用性。
2. 策略模式提供了可以替換繼承關係的辦法。繼承也可以處理多種算法行爲,如果不使用策略模式,那麼使用算法或行爲的環境類就可能有一些子類,每個子類提供一個不同的算法,這樣的話,算法或行爲的使用者就    和算法本身混在一起,從而不可能在獨立的演化。
3. 使用策略可以避免多重條件轉移語句。

策略模式的一些缺點:
1. 客戶端必須知道所有的具體策略模式,並自行決定調用哪一個,這對擁有大量策略的應用是困難的。
2. 策略模式會造成很多策略類。有時候可以通過把依賴於環境的狀態保存到客戶端裏面,而將策略類設計成可共享的,這樣的策略類實例可以被不同的客戶端使用。一顆使用享元模式來減少對象的數量。

使用策略模式的場景:
1. 多個類只是在算法或行爲上稍有不同的場景。
2. 算法需要自由切換的場景。
3. 需要屏蔽算法規則的場景。



發佈了65 篇原創文章 · 獲贊 34 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章