• 请不要在回答技术问题时复制粘贴 AI 生成的内容
hyyy
V2EX  ›  程序员

如何完美的消除 if...else..或者 switch 这种代码,求大神给个思路。

  •  
  •   hyyy · Jun 30, 2016 · 18810 views
    This topic created in 3783 days ago, the information mentioned may be changed or developed.

    举个例子,在 iOS 开发中,经常会遇到在设置 tableViewCell 时需要根据 indexPath 来设置不同 cell ,一般代码可能会是下面这个样子:

    - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
        
        // 设置第一种 cell
        if (indexPath.section == 3 && indexPath.row != 2) {
            //  cell 代码
            return cell;
        }
        
        // 设置第二种 cell
        if (indexPath.section == 3 && indexPath.row == 2) {
            // cell 代码
            return cell;
        }
        
        // 设置其他 cell
        return cell;
    }
    
    

    当然,举的例子比较简单, if...else...也不多,这种场景在开发中很多,一般使用 if...else...或者 switch 时会使代码非常多,求大神们能不能给个思路,遇到这种场景尽量不要出现这种嵌套代码,最好给个实例膜拜膜拜 ^_^

    86 replies  •  2016-07-01 22:17:23 +08:00
    wander2008
    wander2008
    Jun 30, 2016 via iPhone
    1
    不可能
    ourcubk
    ourcubk
    Jun 30, 2016
    2
    不可能
    chairuosen
    chairuosen
    Jun 30, 2016
    3
    switch 可以打表,简单 if 也可以
    zhuangzhuang1988
    zhuangzhuang1988
    Jun 30, 2016❤️4
    4
    1. 表驱动法(看: 代码大全)
    2. 使用 match(看: F#, Scala)'
    3. 使用类+继承(看: 设计模式)
    Jabin
    Jabin
    Jun 30, 2016
    5
    封装 工厂
    ipconfiger
    ipconfiger
    Jun 30, 2016❤️1
    6
    该用则用, if else 是基础逻辑, 如果不是深层次嵌套的话, 最好不要作一些奇技淫巧出来
    hyyy
    hyyy
    OP
    Jun 30, 2016
    7
    @wander2008
    其实我觉得这是一个有趣的话题^_^
    kera0a
    kera0a
    Jun 30, 2016
    8
    SEL methods[][3] = {
    { @selector(getFirstCell:) },
    { @selector(getSecondCell:) },
    { @selector(getThirdCell:) },
    };

    SEL sel = methods[indexPath.section][indexPath.row];
    [self performSelector:sel withObject:indexPath];
    hasbug
    hasbug
    Jun 30, 2016
    9
    这能避免吗? 除非不做判断···
    stcasshern
    stcasshern
    Jun 30, 2016
    10
    这个不能吧,印象中这个是最基础得
    ma125125t
    ma125125t
    Jun 30, 2016
    11
    目前的 tableView 就是这么艹蛋。但已经有很多开源的方法解决这个问题了(想象一下一百种 cell ,分为数十个 section 和 row 的情况)。去找找吧。
    michaelye1988
    michaelye1988
    Jun 30, 2016❤️2
    12
    我认为这种情况下用 if else 或者 switch 是非常合理的,至少代码可读性还是在的。如果非要套用一些设计模式什么的,维护起来就痛苦了。
    chmlai
    chmlai
    Jun 30, 2016
    13
    这个简单, 用数据驱动就清晰多了
    spongebobsun
    spongebobsun
    Jun 30, 2016
    14
    @kera0a 学习了
    mygirl
    mygirl
    Jun 30, 2016
    15
    @ma125125t 几十种的 Cell 这应该是属于不合理的设计吧?
    chunqiuyiyu
    chunqiuyiyu
    Jun 30, 2016
    16
    完美消除是不可能的,不然这几个关键字就不会出现。重要的是理清逻辑,不要嵌套过深。
    rekulas
    rekulas
    Jun 30, 2016
    17
    看不懂 两种都是返回 cell 条件为什么不整合在一起
    8bit
    8bit
    Jun 30, 2016 via Android
    18
    查表,代码大全
    subpo
    subpo
    Jun 30, 2016
    19
    能只写 if 不写 else 不错了
    harry890829
    harry890829
    Jun 30, 2016
    20
    这种平级的 if...else...已经不错了,我刚接手了一个代码,到手的时候 4-5 层 if 结构嵌套,全都带 else ,因为需求的关系,我现在又在里面加了两层 if..else...结构,我已经恶心死了
    woshicixide
    woshicixide
    Jun 30, 2016 via Android
    21
    多态
    jason19659
    jason19659
    Jun 30, 2016
    22
    cell = indexPath.section == 3 ? a : indexPath.row == 2 ? b : c
    zhicheng
    zhicheng
    Jun 30, 2016
    23
    静态结构这样写没问题,把 3 和 2 消除就行,用 USER_SECTION 常量定义一下。
    动态结构用 model 来判断。
    fatedier
    fatedier
    Jun 30, 2016
    24
    简单工厂模式 + 反射,可以实现根据不同的字符串执行不同业务逻辑,但是不适合用这个替换掉所有的 if-else ,不然就是过度设计了。

    之前用 c++ 写过一个例子: http://blog.fatedier.com/2015/03/04/decoupling-by-using-reflect-and-simple-factory-pattern-in-cpp/
    lingoerer
    lingoerer
    Jun 30, 2016
    25
    1 :[CellViewModel] -> 把每一个 Cell 的 ViewModel 定义出来,放进数组
    2 : cellViewModel.identifier, cell.render(cellViewModel) -> 每个 ViewModel 定义自己要用什么 Cell 来展示, dequeue 的时候出不同的 Cell ,然后 Cell 自己对应着绑 UI
    3 : tableView 的回调中直接一行同样的代码把 Cell 弄出来

    当然,前面还有个:
    0 :把你要显示的 Model 的内容 map 成 CellViewModel 的数组
    muller
    muller
    Jun 30, 2016
    27
    策略模式
    davisz
    davisz
    Jun 30, 2016
    28
    do {
    if (false) break;
    }while(0);
    ilotuo
    ilotuo
    Jun 30, 2016
    29
    这样?
    ```java
    cell = indexPath.section == 3 ? CellFactory.build(...) : indexPath.row == 2 ? CellFactory.build(...): null;
    ```
    xwartz
    xwartz
    Jun 30, 2016
    30
    map
    mdluo
    mdluo
    Jun 30, 2016
    31
    分支存数组,条件用位运算
    ihuotui
    ihuotui
    Jun 30, 2016 via Android
    32
    责任连模式,差不多
    hantsy
    hantsy
    Jun 30, 2016
    33
    State 模式
    twoyuan
    twoyuan
    Jun 30, 2016
    34
    首先应该消灭的不是 Magic Number 吗……
    sutra
    sutra
    Jun 30, 2016
    35
    Map
    youyongsong
    youyongsong
    Jun 30, 2016
    36
    pattern match
    0x5e
    0x5e
    Jun 30, 2016
    37
    swift 可能会稍微简化点
    let path = (indexPath.section, indexPath.row)
    switch(path) {
    case (0, 0):
    //xxxx
    case (0, 1):
    //xxxx
    }
    JasperYanky
    JasperYanky
    Jun 30, 2016
    38
    model 决定 view controller 层不关心数据 只负责传递
    loveuqian
    loveuqian
    Jun 30, 2016
    40
    之前也是这样判断行数,后来改判断模型 title 了
    因为判断行数,一不小心,在第 0 行前面加一行,你这所有判断都要重写啊。。
    vincentxue
    vincentxue
    Jun 30, 2016
    41
    看来 iOS 迫切需要一个为 UITableView 或者 UICollectionView 解决数据源封装的库。
    sensui7
    sensui7
    Jun 30, 2016
    42
    OO 中的 tell, don't ask 原则可以消除这种大量的 else , if else 多说明代码抽象的不好, 根据你的逻辑,可以采用相应的设计模式解决
    lalalafq
    lalalafq
    Jun 30, 2016
    43
    所有的数据源逻辑(高度,点击,渲染)全部丢到一个 array ;基础的 tableView 委托永远只有大概 10 行左右;
    绝壁高聚合,低耦合;产品想怎么改就怎么改;顺序啥的都是小问题。
    JohnSmith
    JohnSmith
    Jun 30, 2016
    44
    rust 中有个 match
    skyoojaa
    skyoojaa
    Jun 30, 2016 via Android
    45
    If...else...没法消除,但可以封装判断,让 if...else...里面的代码看起来简洁一些
    realpg
    realpg
    Jun 30, 2016
    46
    我觉得这种代码很好
    瞎搞弄得可维护性差才是大坑
    dorentus
    dorentus
    Jun 30, 2016
    48
    @realpg 在最前面加一行的话,要从上到下把数字都改掉,也叫可维护性好么……
    so898
    so898
    Jun 30, 2016
    49
    真要很多的话不应该是自定义 Cell ,然后把代码放到 Cell 里面去么?
    如果说不能自定义 Cell ,那不是应该通过在外面建立 Cell 内容填充生成的方法来做到精简这一块的代码么?
    missdeer
    missdeer
    Jun 30, 2016
    50
    你看,用 OO 设计模式的时候到了,上面说不行的都不是那个年代过来的人
    weirdyu
    weirdyu
    Jun 30, 2016
    51
    你这种按照行数来判断返回何种 cell 的方式不太好
    zjyjer
    zjyjer
    Jun 30, 2016
    52
    1. 模式匹配
    2. 设计一个状态机 每个分支里的代码抽象出一个函数异步调用之
    programgou
    programgou
    Jun 30, 2016
    53
    我认为我们可以专门提供一个 indexPath 的接口,然后再提供一个 builder ,把实现了 indexPath 接口的类的实例传递给 builder , builder 就可以返回一个 cell 。这样无论你有多少种 indexPath ,只需要维护 builder ,而不会改变 tableView 的任何代码。当你觉得你现在的 builder 过于复杂的时候,你甚至可以为这个 builder 提供接口,这样你可以在不改变原来代码的基础上,替换掉原来的 builder 。总之,类与类建立关系要通过接口,这样就可以在不改变代码的基础上,换掉一个类。也就是换掉一个功能。

    这里面涉及到一些设计模式的东西,不过楼主别怕,看不懂书建议去看源码,我博客上写过一个关于建构者模式的分析,你可以参考一下,不过要解决你的问题一个建构者模式肯定是不够的,还有工厂模式。
    sablib
    sablib
    Jun 30, 2016
    54
    如果是 swift 的话,就用 enum 了。
    billion
    billion
    Jun 30, 2016
    55
    如果语言是 Python 的话,可以使用字典解决:
    ```
    def a(para):
    xxx

    def b(para):
    xxx

    def c(para):
    xxx

    functionDict = {'a':a, 'b': b, 'c': c}

    result = functionDict[name](para)
    ```
    这样,当你需要使用 switch 或者 if ...else 来调用函数的时候,可以通过: functionDict('a')(para)这种方式调用函数。
    chrisstyle
    chrisstyle
    Jun 30, 2016
    56
    同 25 楼~
    推荐
    i4mszengg
    i4mszengg
    Jun 30, 2016
    57
    我想应该不用故意写一些奇葩的逻辑,日后维护很痛苦的吧,如果 单个 if 的 condiftions 比较多,可以嵌套 if , 这样更容易懂些,日后好维护。
    jasonlz
    jasonlz
    Jun 30, 2016
    58
    用状态机。
    ooonme
    ooonme
    Jun 30, 2016 via iPhone
    59
    @zjyjer 正解
    djyde
    djyde
    Jun 30, 2016
    60
    程序之所以是程序,因为它能 if else
    EAimTY
    EAimTY
    Jun 30, 2016 via Android
    61
    不可能的,不论用什么方法代替,底层肯定还会是 if else
    adrianzhang
    adrianzhang
    Jun 30, 2016 via Android
    62
    结构化语言之前,都用 goto ,汇编里见 jump 更多。
    xwing
    xwing
    Jun 30, 2016
    63
    命令链模式。
    hrong
    hrong
    Jun 30, 2016 via Android
    64
    表驱动,策略模式。

    有人说什么反射,想想反射里面有多少个 if/else 就知道用反射有多么的得不偿失
    cocoaChina
    cocoaChina
    Jun 30, 2016 via Android
    65
    这种判断逻辑必须有,但逻辑内实现却可以瘦身,尽量多用 switch
    powergx
    powergx
    Jun 30, 2016 via iPhone❤️1
    66
    cpu 晶体管可是只有通河短两种情况, lz 竟然说不用 if
    rashawn
    rashawn
    Jun 30, 2016
    67
    最下面都是一样的吧 不用这个是不是能跑的快一点
    cheng4741
    cheng4741
    Jun 30, 2016
    68
    @EAimTY 并不会,这种情况用表或数组的话,再底层也不会有 if else
    aias
    aias
    Jun 30, 2016
    69
    @mygirl Hello ,宁波的同学,又看到你了!招人还顺吗?
    peneazy
    peneazy
    Jun 30, 2016 via Android
    70
    我只知道 js 怎么消除这种东西。利用多态性,比如原型继承,把每一种可能封装在原型里,构造函数直接调用。看看设计模式吧,有至少两种模式能大幅度减少判断语句。
    holy_sin
    holy_sin
    Jun 30, 2016
    71
    问题的核心就是区分出不同类型的 cell 要如何渲染。如果在 vc 里做,那么 collectionView 对应的所有 datasource 和 delegate 都需要分别写一套区分方法。所以比较好的方法是在构造数据源的时候,指定好每一种 cell 如何显示。由于 cell 信息可能会比较多,所以就衍生出来用 cellViewModel 来管理这些信息,这就是数据驱动的意思吧。当 cell 的排列关系需要改动的时候,只需要修改构造数据源的地方。其实就是 @lingoerer 所说的做法。
    hinkal
    hinkal
    Jun 30, 2016
    72
    利用多态减少 if else 才是正解,否则说明上下文中 if else 不应该被消除。
    tutuge
    tutuge
    Jul 1, 2016
    74
    模板方法解决, cell 基类,传入 index 等参数,让 cell 不同子类自己处理。也就是多态=。=
    yangff
    yangff
    Jul 1, 2016 via Android
    75
    @zhuangzhuang1988 讲道理 switch 本来就是 jump table ,编译器还会把它塞到 ro 的段上,安全性还更好些
    arakashic
    arakashic
    Jul 1, 2016
    76
    @yangff 实际上编译器并不总是把 switch 生成成 jump table 。
    wangyifei6817
    wangyifei6817
    Jul 1, 2016
    77
    这里不谢 也要写到别的地方 换个地方恶心而已
    miaotaizi
    miaotaizi
    Jul 1, 2016
    78
    策略模式?
    wander2008
    wander2008
    Jul 1, 2016 via iPhone
    79
    @hyyy 是的,逻辑层面确实不行。
    搞设计模式可以。 java
    wmhx
    wmhx
    Jul 1, 2016
    80
    java 的工厂模式. 参见 jfinal
    eimsteim
    eimsteim
    Jul 1, 2016
    81
    @ihuotui 这跟责任链有毛线关系,学设计模式都学傻了吧
    coa
    coa
    Jul 1, 2016
    82
    @lingoerer 学习了。。请教下这种是不是得把所有 ViewModel 都放同一数组了,不同 Cell 连续存放倒还好办,如果是交叉着放还能用这办法吗?
    yangff
    yangff
    Jul 1, 2016
    83
    @arakashic 编译器会选择合理的方式来生成代码
    bobuick
    bobuick
    Jul 1, 2016
    84
    模式匹配吧, rust 或 haskell 那种模式匹配方式,不过完全杜绝是不可能的, 不过可以大部分解决了
    nozama
    nozama
    Jul 1, 2016 via iPhone
    85
    这种情况 mvvm 吧, datasource 里面只存放一堆抽象的 cellViewModel ,并通过工厂来获得具体的 cell ,工厂可以用数据来驱动。
    Balthild
    Balthild
    Jul 1, 2016
    86
    全部用 goto
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1673 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 207ms · UTC 13:22 · PVG 21:22 · LAX 05:22 · JFK 08:22
    ♥ Do have faith in what you're doing.