策略設計模式

引言

這是在項目開發過程中的需求:
用戶Zing_LYF在photo2頻道中發布了內容為“是不是真的”的感言,除了頭部的展示內容不同,其他都一樣。
(1)在個人中心,感言頭部顯示該感言所屬頻道的頻道icon和頻道名稱,點擊icon,跳轉到頻道詳情
(2)在頻道詳情,感言頭部展示發布此感言的用戶頭像和用戶名,點擊頭像,跳轉該用戶的個人中心


感言在個人中心的展示模式
感言在頻道詳情的展示模式

一般的思路:
cell的布局一模一樣,但是在給cell綁定感言模型的時候,同時傳一個模塊參數表示是個人中心 還是 頻道詳情,然后在cell里面再通過if else 判斷不同的模塊,處理不同的邏輯。

問題

隨著以后模塊的繼續增加,cell中會有很多if else 的邏輯判斷,顯得邏輯很混亂,代碼很冗余。

思考

我們發現這兩個模塊的感言數據是一樣的,但是部分的展示模式隨著模塊的不同而不同,這幾引出我們今天的設計模式——策略設計模式

策略設計模式

1.概念

策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。

2.組成

  • 抽象策略角色: 策略類,通常由一個接口或者抽象類實現。
  • 具體策略角色:包裝了相關的算法和行為。
  • 環境角色:持有一個策略類的引用,最終給客戶端調用。

3.概念

Context(應用場景):
1、需要使用ConcreteStrategy提供的算法。
2、 內部維護一個Strategy的實例。
3、 負責動態設置運行時Strategy具體的實現算法。
4、負責跟Strategy之間的交互和數據傳遞。
Strategy(抽象策略類):
1、 定義了一個公共接口,各種不同的算法以不同的方式實現這個接口,Context使用這個接口調用不同的算法,一般使用接口或抽象類實現。
ConcreteStrategy(具體策略類):
2、 實現了Strategy定義的接口,提供具體的算法實現。

4.UML類圖

5.使用

1.抽象策略類:SenseHeaderDisplayStrategy(感言頭部展示策略)

@interface SenseHeaderDisplayStrategy : NSObject<SenseHeaderDisplayStrategy>

@end

2.抽象策略類定義的一系列接口:

/**
 頭部視圖策略接口的定義
 */
@protocol SenseHeaderDisplayStrategy <NSObject>

@optional

/**
 獲取頭像URL

 @param sense sense
 @return 頭像URL
 */
- (NSString *)getIconUrlWithSense:(ZTMSense *)sense;

/**
 獲取標題文本

 @param sense sense
 @return 標題文本
 */
- (NSString *)getTitleTextWithSense:(ZTMSense *)sense;

/**
 點擊頭像邏輯跳轉

 @param sense sense
 @param delegate 代理
 */
- (void)triggerIconClickWithSense:(ZTMSense *)sense delegate:(id<SenseCellDelegate>)delegate;

@end

3.具體策略類:SenseHeaderDisplay4Channel(頭部展示頻道信息的策略類)
實現具體的接口:

#pragma mark - SenseHeaderDisplayStrategy

- (NSString *)getIconUrlWithSense:(ZTMSense *)sense{
    //頻道icon
    return [ZingFileManager getPortrait:sense.channel.icon];
}

- (NSString *)getTitleTextWithSense:(ZTMSense *)sense {
    //頻道名稱
    return sense.channel.name;
}

- (void)triggerIconClickWithSense:(ZTMSense *)sense delegate:(id<SenseCellDelegate>)delegate {
    //跳轉頻道詳情
    [self onNavigationToChannelWithSense:sense];
}

- (void)onNavigationToChannelWithSense:(ZTMSense *)sense {
    [[ZingManager getCurrentViewController] gotoChannelWithId:sense.channelId];
}

4.具體策略類:SenseHeaderDisplay4Person(頭部展示個人信息的策略類)
實現具體的接口:

#pragma mark - SenseHeaderDisplayStrategy

- (NSString *)getIconUrlWithSense:(ZTMSense *)sense {
    //用戶頭像
    return [ZingFileManager getPortrait:sense.user.avatar];
}

- (NSString *)getTitleTextWithSense:(ZTMSense *)sense {
    //用戶名
    return sense.user.userName;
}

- (void)triggerIconClickWithSense:(ZTMSense *)sense delegate:(id<SenseCellDelegate>)delegate {
    //跳轉用戶個人中心
    [self onNavigationToPersonWithUser:sense.user];
}

- (void)onNavigationToPersonWithUser:(ZTMUserDescription *)user {
    [[ZingManager getCurrentViewController] gotoProfileWithUserId:user.id_p];
}

5.在對應的模塊實例對應的策略類,讓cell持有對應策略類,調用對應具體策略類的實現
(1)頻道詳情的頁面,調用展示用戶信息的策略類

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ZTMSenseLayout *layout;
    if (indexPath.section == 0) {
        layout = self.draftLayouts[indexPath.row];
    }else{
        layout = self.senseLayouts[indexPath.row];
    }
    SenseCell *cell = [SenseCell cellWithTableView:tableView delegate:self type:layout.sense.content.mediaType headerDisplayStrategy:[SenseHeaderDisplay4Personal defaultDisplayStrategy]];
    [layout setIndexPath:indexPath];
    if (layout.tableView != tableView) layout.tableView = tableView;
    [cell layoutSubviewsWithLayout:layout];
    return cell;
}

(2)個人中心的頁面,調用展示頻道信息的策略類

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ZTMSenseLayout *layout;
    if (indexPath.section == 0) {
        layout = self.draftLayouts[indexPath.row];
    } else {
        layout = self.senseLayouts[indexPath.row];
    }
    SenseCell *cell = [SenseCell cellWithTableView:tableView delegate:self type:layout.sense.content.mediaType headerDisplayStrategy:[SenseHeaderDisplay4Channel defaultDisplayStrategy]];
    [layout setIndexPath:indexPath];
    if (layout.tableView != tableView) layout.tableView = tableView;
    [cell layoutSubviewsWithLayout:layout];
    return cell;
}

6.在cell布局的時候調用策略類


/** 頭部顯示策略 */
@property (nonatomic, strong) SenseHeaderDisplayStrategy *headerDisplayStrategy;

/**
 布局
 
 @param layout 布局
 */
- (void)layoutSubviewsWithLayout:(ZTMSenseLayout *)layout {
    [super layoutSubviewsWithLayout:layout];
    
    //設置頭像,調用策略類
    [self.avatar_imageView sd_setImageWithURL:[ZingFileManager getPortraitURLWithString:[self.headerDisplayStrategy getIconUrlWithSense:layout.sense]] placeholderImage:[UIImage avatarPlaceholder] options:SDWebImageLowPriority];
    
    //設置名字,調用策略類
    _userName_label.text = [_headerDisplayStrategy getTitleTextWithSense:layout.sense];
}

[self.avatar_imageView addTapGestureBlock:^{
        //點擊頭像,調用策略類
        [weak_self.headerDisplayStrategy triggerIconClickWithSense:weak_self.sense delegate:weak_self.delegate];
    }];

6.優缺點

優點:

1、 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族。恰當使用繼承可以把公共的代碼轉移到父類里面,從而避免重復的代碼。
2、 策略模式提供了可以替換繼承關系的辦法。繼承可以處理多種算法或行為。如果不是用策略模式,那么使用算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的算法或行為。但是,這樣一來算法或行為的使用者就和算法或行為本身混在一起。決定使用哪一種算法或采取哪一種行為的邏輯就和算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變算法或行為變得不可能。
3、 使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統統列在一個多重轉移語句里面,比使用繼承的辦法還要原始和落后。

缺點:

1、客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
2、 策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴于環境的狀態保存到客戶端里面,而將策略類設計成可共享的,這樣策略類實例可以被不同客戶端使用。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容