一、概念
1、策略模式的動機
? 雙十一是電商狂歡節,各種商品都會打折,而且打折的算法又是千奇百怪,比如滿多少錢打8折,滿多少錢減200塊,滿多少錢送一件等。在軟件開發中,實現某一個功能有多條途徑,每一條途徑對應一種算法,此時我們可以使用一種設計模式來實現靈活地選擇解決途徑,也能夠方便地增加新的解決途徑,這就是為了適應算法靈活性而產生的設計模式——策略模式。
2、策略模式的定義
? 策略模式(Strategy Pattern):定義一系列算法類,將每一個算法封裝起來,并讓它們可以相互替換,策略模式讓算法獨立于使用它的客戶而變化,也稱為政策模式(Policy)。策略模式是一種對象行為型模式。
? 策略模式的主要目的是將算法的定義與使用分開,將算法的定義放在專門的策略類中,每一個具體策略類封裝了一種實現算法,使用算法的環境類針對抽象策略類進行編程,符合“依賴倒轉原則”。在出現新的算法時,只需要增加一個新的實現了抽象策略類的具體策略類即可。
3、策略模式的3個角色
1)Context(環境類):環境類是使用算法的角色,它在解決某個問題(即實現某個方法)時可以采用多種策略。在環境類中維持一個對抽象策略類的引用實例,用于定義所采用的策略。
2)Strategy(抽象策略類):它為所支持的算法聲明了抽象方法,是所有策略類的父類,它可以是抽象類或具體類,也可以是接口。環境類通過抽象策略類中聲明的方法在運行時調用具體策略類中實現的算法。
3)ConcreteStrategy(具體策略類):它實現了在抽象策略類中聲明的算法,在運行時,具體策略類將覆蓋在環境類中定義的抽象策略類對象,使用一種具體的算法實現某個業務處理。
4、結構圖
二、示例
? 策略模式通常把一個系列的算法封裝到一系列具體策略類里面,作為抽象策略類的子類。環境類是需要使用算法的類,在一個系統中可以存在多個環境類,它們可能需要重用一些相同的算法。
1)先定義一個SortingStrategy協議,是排序算法協議,表示抽象策略類;
2)然后創建四個類BubbleSort、SelectionSort、InsertionSort和QuickSort,并遵循于SortingStrategy協議,表示具體策略類;
3)最后創建Context類,有一個strategy屬性,表示環境類。
SortingStrategy協議:
// 排序算法策略
@protocol SortingStrategy <NSObject>
- (NSArray *)sortingAlgorithmWithArray:(NSArray *)array; //聲明抽象算法
@end
typedef id<SortingStrategy> SortingStrategy;
BubbleSort、SelectionSort、InsertionSort和QuickSort類:
// BubbleSort 冒泡排序
@interface BubbleSort : NSObject<SortingStrategy>
@end
@implementation BubbleSort
- (NSArray *)sortingAlgorithmWithArray:(NSArray *)array {
NSLog(@"使用冒泡排序算法");
return [NSArray array]; //這里省略具體算法
}
@end
// SelectionSort 選擇排序
@interface SelectionSort : NSObject<SortingStrategy>
@end
@implementation SelectionSort
- (NSArray *)sortingAlgorithmWithArray:(NSArray *)array {
NSLog(@"使用選擇排序算法");
return [NSArray array]; //這里省略具體算法
}
@end
// InsertionSort 插入排序
@interface InsertionSort : NSObject<SortingStrategy>
@end
@implementation InsertionSort
- (NSArray *)sortingAlgorithmWithArray:(NSArray *)array {
NSLog(@"使用插入排序算法");
return [NSArray array]; //這里省略具體算法
}
@end
// QuickSort 快速排序
@interface QuickSort : NSObject<SortingStrategy>
@end
@implementation QuickSort
- (NSArray *)sortingAlgorithmWithArray:(NSArray *)array {
NSLog(@"使用快速排序算法");
return [NSArray array]; //這里省略具體算法
}
@end
Context類:
// 環境類:使用算法的角色
@interface Context : NSObject
@property(nonatomic, strong) SortingStrategy strategy; //維持一個對抽象策略類的引用
- (instancetype)initWithStrategy:(SortingStrategy)strategy;
- (NSArray *)sortWithArray:(NSArray *)array;
@end
@implementation Context
- (instancetype)initWithStrategy:(SortingStrategy)strategy {
self = [super init];
if (self) {
_strategy = strategy;
}
return self;
}
- (NSArray *)sortWithArray:(NSArray *)array {
return [self.strategy sortingAlgorithmWithArray:array]; //調用策略類中的算法
}
@end
運行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
SortingStrategy bubble = [BubbleSort new];
Context *context1 = [[Context alloc] initWithStrategy:bubble];
[context1 sortWithArray:@[@3, @1, @2]];
SortingStrategy selection = [SelectionSort new];
Context *context2 = [[Context alloc] initWithStrategy:selection];
[context2 sortWithArray:@[@6, @8, @7]];
}
打印結果:
使用冒泡排序算法
使用選擇排序算法
三、總結
? 策略模式用于算法的自由切換和擴展,它是應用較為廣泛的設計模式之一。策略模式對應于解決某一問題的一個算法族,允許用戶從該算法族中任選一個算法來解決某一問題,同時可以方便地更換算法或者增加新的算法。只要涉及到算法的封裝、復用和切換都可以考慮使用策略模式。
1、優點
1、策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統的基礎上選擇算法或行為,也可以靈活地增加新的算法或行為。
2、策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族,恰當使用繼承可以把公共的代碼移到抽象策略類中,從而避免重復的代碼。
3、策略模式提供了一種可以替換繼承關系的辦法。如果不使用策略模式,那么使用算法的環境類就可能會有一些子類,每一個子類提供一種不同的算法。但是,這樣一來算法的使用就和算法本身混在一起,不符合“單一職責原則”,決定使用哪一種算法的邏輯和該算法本身混合在一起,從而不可能再獨立演化;而且使用繼承無法實現算法或行為在程序運行時的動態切換。
4、策略模式提供了一種算法的復用機制,由于將算法單獨提取出來封裝在策略類中,因此不同的環境類可以方便地復用這些策略類。
2、缺點
1、客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區別,以便適時選擇恰當的算法。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
2、策略模式將造成系統產生很多具體策略類,任何細小的變化都將導致系統要增加一個新的具體策略類。
3、無法同時在客戶端使用多個策略類,也就是說,在使用策略模式時,客戶端每次只能使用一個策略類,不支持使用一個策略類完成部分功能后再使用另一個策略類來完成剩余功能的情況。
3、適用場景
1、一個系統需要動態地在幾種算法中選擇一種,那么可以將這些算法封裝到一個個的具體算法類中。
2、不希望客戶端知道復雜的、與算法相關的數據結構,在具體策略類中封裝算法與相關的數據結構,可以提高算法的保密性與安全性。
4、iOS應用舉例
? 在MVC模式中,控制器決定視圖對模型數據進行顯示的時機和內容。視圖本身知道如何繪圖,但需要控制器告訴它要顯示的內容。同一個視圖如果與不同的控制器合作,數據內容隨著不同控制器而不同,這個時候控制器就是視圖的策略。
Demo地址:iOS-Design-Patterns