zoukankan      html  css  js  c++  java
  • 使用工厂模式定制UITableViewCell

    背景:最近在进行list页重构,list页的cell会有不同的展现形式,即同一个UITableView上多种cell并存。为了响应这种需求,我们考虑通过cell容器化的方式解决该问题。最理想的解决方法就是通过工厂模式来定制这些cell,当服务端告知我们某一个indexPath的cell的style时,我们就用相应类型的cell去填充。

    工厂模式介绍

    工厂模式可以分为简单工厂模式, 工厂方法模式, 抽象工厂模式,这三种模式在设计程度上由简单到复杂。下面挨个解释下各自的特点。

    简单工厂模式

    简单工厂模式是由工厂类直接生产相应的产品(通过类方法),然后在方法中通过switch-case 语句(或者if-else 语句)来决定胜场什么产品。该模式算是工厂模式的一个特例,因为当用户需要新增一种产品时,需要在直接修改工厂方法的switch-case 语句(或if-else 语句),通过添加分支条件来适应更多种情况,由此看出,它违背了开放-封闭原则。

    @interface TRIPHotelCellFactory : NSObject

    /**

     *  cell工厂方法

     *

     *  @param cellClassName 待新建的cell类名

     *  @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;

    }

     

  • 相关阅读:
    凤凰架构-读书笔记
    《团队协作的五大障碍》笔记
    MongoDB基本操作命令一
    NBI可视化集成clickhouse,实现百亿级数据分析能力
    AI文本与图像数据集荟萃
    gitLab内网部署
    git管理子模块
    git基础使用
    linux内核数据结构之链表-再实现
    win10下安装linux子系统
  • 原文地址:https://www.cnblogs.com/ranger-jlu/p/4932023.html
Copyright © 2011-2022 走看看