策略設(shè)計(jì)模式

引言

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


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

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

問題

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

思考

我們發(fā)現(xiàn)這兩個(gè)模塊的感言數(shù)據(jù)是一樣的,但是部分的展示模式隨著模塊的不同而不同,這幾引出我們今天的設(shè)計(jì)模式——策略設(shè)計(jì)模式

策略設(shè)計(jì)模式

1.概念

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

2.組成

  • 抽象策略角色: 策略類,通常由一個(gè)接口或者抽象類實(shí)現(xiàn)。
  • 具體策略角色:包裝了相關(guān)的算法和行為。
  • 環(huán)境角色:持有一個(gè)策略類的引用,最終給客戶端調(diào)用。

3.概念

Context(應(yīng)用場(chǎng)景):
1、需要使用ConcreteStrategy提供的算法。
2、 內(nèi)部維護(hù)一個(gè)Strategy的實(shí)例。
3、 負(fù)責(zé)動(dòng)態(tài)設(shè)置運(yùn)行時(shí)Strategy具體的實(shí)現(xiàn)算法。
4、負(fù)責(zé)跟Strategy之間的交互和數(shù)據(jù)傳遞。
Strategy(抽象策略類):
1、 定義了一個(gè)公共接口,各種不同的算法以不同的方式實(shí)現(xiàn)這個(gè)接口,Context使用這個(gè)接口調(diào)用不同的算法,一般使用接口或抽象類實(shí)現(xiàn)。
ConcreteStrategy(具體策略類):
2、 實(shí)現(xiàn)了Strategy定義的接口,提供具體的算法實(shí)現(xiàn)。

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;

/**
 獲取標(biāo)題文本

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

/**
 點(diǎn)擊頭像邏輯跳轉(zhuǎn)

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

@end

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

#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 {
    //跳轉(zhuǎn)頻道詳情
    [self onNavigationToChannelWithSense:sense];
}

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

4.具體策略類:SenseHeaderDisplay4Person(頭部展示個(gè)人信息的策略類)
實(shí)現(xiàn)具體的接口:

#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 {
    //跳轉(zhuǎn)用戶個(gè)人中心
    [self onNavigationToPersonWithUser:sense.user];
}

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

5.在對(duì)應(yīng)的模塊實(shí)例對(duì)應(yīng)的策略類,讓cell持有對(duì)應(yīng)策略類,調(diào)用對(duì)應(yīng)具體策略類的實(shí)現(xiàn)
(1)頻道詳情的頁(yè)面,調(diào)用展示用戶信息的策略類

- (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)個(gè)人中心的頁(yè)面,調(diào)用展示頻道信息的策略類

- (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布局的時(shí)候調(diào)用策略類


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

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

[self.avatar_imageView addTapGestureBlock:^{
        //點(diǎn)擊頭像,調(diào)用策略類
        [weak_self.headerDisplayStrategy triggerIconClickWithSense:weak_self.sense delegate:weak_self.delegate];
    }];

6.優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

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

缺點(diǎn):

1、客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴?。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
2、 策略模式造成很多的策略類,每個(gè)具體策略類都會(huì)產(chǎn)生一個(gè)新類。有時(shí)候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面,而將策略類設(shè)計(jì)成可共享的,這樣策略類實(shí)例可以被不同客戶端使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容