使用工廠模式定製UITableViewCell

背景:最近在進行list頁重構,list頁的cell會有不一樣的展示形式,即同一個UITableView上多種cell並存。爲了響應這種需求,咱們考慮經過cell容器化的方式解決該問題。最理想的解決方法就是經過工廠模式來定製這些cell,當服務端告知咱們某一個indexPath的cell的style時,咱們就用相應類型的cell去填充。spa

 

工廠模式介紹設計

工廠模式能夠分爲簡單工廠模式, 工廠方法模式, 抽象工廠模式,這三種模式在設計程度上由簡單到複雜。下面挨個解釋下各自的特色。orm

 

簡單工廠模式對象

簡單工廠模式是由工廠類直接生產相應的產品(經過類方法),而後在方法中經過switch-case 語句(或者if-else 語句)來決定勝場什麼產品。該模式算是工廠模式的一個特例,由於當用戶須要新增一種產品時,須要在直接修改工廠方法的switch-case 語句(或if-else 語句),經過添加分支條件來適應更多種狀況,由此看出,它違背了開放-封閉原則。索引

@interface TRIPHotelCellFactory : NSObject接口

/**開發

 *  cell工廠方法字符串

 *產品

 *  @param cellClassName 待新建的cell類名it

 *  @param cellModel     cell數據模型

 *  @param indexPath     index索引

 *

 *  @return 目標cell

 */

+ (TRIPHotelBasicCell *)creatCellWithClassName:(NSString *)cellClassName

                                     cellModel:(TRIPHotelCellModel *)cellModel

                                     indexPath:(NSIndexPath *)indexPath;

@end

 

@implementation TRIPHotelCellFactory

 

+ (TRIPHotelBasicCell *)creatCellWithClassName:(NSString *)cellClassName

                                     cellModel:(TRIPHotelCellModel *)cellModel

                                     indexPath:(NSIndexPath *)indexPath{

    TRIPHotelBasicCell *cell = nil;

    

    if ([cellClassName isEqualToString:@"TRIPHotelStandardCell"]) {

        cell = [[TRIPHotelStandardCell alloc] initWithStyle:UITableViewCellStyleDefault

                                            reuseIdentifier:@"TRIPHotelStandardCell"];

    } else if ([cellClassName isEqualToString:@"TRIPHotelForSaleCell"]){

        cell = [[TRIPHotelForSaleCell alloc] initWithStyle:UITableViewCellStyleDefault

                                           reuseIdentifier:@"TRIPHotelForSaleCell"];

    }

    

    return [cell initData:cellModel indexPath:indexPath];

}

@end

 

工廠方法模式

工廠方法模式不直接生產產品,而是定義好如何生產產品的接口,而後由其子類決定具體生產何種產品,即工廠方法使一個類的實例化延遲到其子類。基類工廠只負責定義接口便可,具體的實現由其子類完成,當須要新增一種產品類型時,只須要再定義一個子類工廠,由該子工廠類去生產相應的產品。很好的知足了開發-封閉的原則。

@interface TRIPHotelCellFactory : NSObject

/**

 *  cell工廠方法

 *

 *  @param cellModel 待新建的cell類名

 *  @param indexPath cell數據模型

 *

 *  @return 目標cell

 */

+ (TRIPHotelBasicCell *)creatCellWithModel:(TRIPHotelCellModel *)cellModel

                                     indexPath:(NSIndexPath *)indexPath;

@end

 

@implementation TRIPHotelCellFactory

+ (TRIPHotelBasicCell *)creatCellWithModel:(TRIPHotelCellModel *)cellModel

                                 indexPath:(NSIndexPath *)indexPath{

    return [[TRIPHotelBasicCell alloc] initWithStyle:UITableViewCellStyleDefault

                                     reuseIdentifier:@"TRIPHotelBasicCell"];

}

@end

 

@interface TRIPHotelForSaleCellFactory : TRIPHotelCellFactory

 

@end

 

@implementation TRIPHotelForSaleCellFactory

 

+ (TRIPHotelBasicCell *)creatCellWithModel:(TRIPHotelCellModel *)cellModel

                                 indexPath:(NSIndexPath *)indexPath{

    TRIPHotelForSaleCell *cell = [[TRIPHotelForSaleCell alloc] initWithStyle:UITableViewCellStyleDefault

                                                             reuseIdentifier:@"TRIPHotelForSaleCell"];

    return [cell initData:cellModel indexPath:indexPath];

}

 

@end

實際上基類工廠方法中返回什麼都無所謂,最終咱們是其子類去生產相應的產品。

 

抽象工廠模式

該工廠模式就更復雜一些了,該工廠類不只能夠生產產品A,還能夠生產產品B,只不過基類工程定義好生產相應產品的方法,尤爲子類去實現具體的產品勝場過程。這個模式用的不是不少,這裏就不舉例了。

 

最佳實踐

從上面的對比能夠發現,簡單工廠模式和工廠方法模式各有好處,一個實現簡單,一個知足開放-封閉原則,支持封閉擴展,若是把這二者的好處融合在一塊兒?

反射機制的引入是這種設想變成可能。

在oc中,反射形如:

NSString *cellClassName = @"TRIPHotelStandardCell";

Class classForCell = NSClassFromString(cellClassName);

能夠直接經過類名便可得到相應的類並實現初始化。

 

修改簡單工廠模式以下:

@implementation TRIPHotelCellFactory

 

+ (TRIPHotelBasicCell *)creatCellWithClassName:(NSString *)cellClassName

                                     cellModel:(TRIPHotelCellModel *)cellModel

                                     indexPath:(NSIndexPath *)indexPath{

    TRIPHotelBasicCell *cell = nil;

    

    // 經過反射來定義cell,當遇到cell拓展時,能夠直接用字符串反射,無需修改該工廠方法

    Class classForCell = NSClassFromString(cellClassName);

    

    // 初始化目標cell

    cell = [[classForCell alloc] initWithStyle:UITableViewCellStyleDefault

                               reuseIdentifier:cellClassName];

    

    return [cell initData:cellModel indexPath:indexPath];

}

 

@end

這樣一來,就能夠在外部直接傳入待生產cell的類名,便可得到相應的對象。當新增cell類型時,只須要在外部傳入新定製的cell類名。該作法使簡單工廠模式知足了封閉-開放原則,並且實現簡單。

其實現形如:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    TRIPHotelCellModel *dataModel = (TRIPHotelCellModel *)self.modelArray[indexPath.row];

    TRIPHotelBasicCell *cell = nil;

    switch (dataModel.cellStyle) {

        case HotelCellStyleStandard:

        {

            cell = [tableView dequeueReusableCellWithIdentifier:@"TRIPHotelStandardCell"];

            if (nil == cell) {

                cell = [TRIPHotelCellFactory creatCellWithClassName:@"TRIPHotelStandardCell"

                                                          cellModel:dataModel

                                                          indexPath:indexPath];

            }

        }

            break;

        case HotelCellStyleForSale:

        {

            cell = [tableView dequeueReusableCellWithIdentifier:@"TRIPHotelForSaleCell"];

            if (nil == cell) {

                cell = [TRIPHotelCellFactory creatCellWithClassName:@"TRIPHotelForSaleCell"

                                                          cellModel:dataModel

                                                          indexPath:indexPath];

            }

        }

            break;

        default:

            break;

    } 

    return cell;

}

相關文章
相關標籤/搜索