V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
twogoods
V2EX  ›  程序员

通过状态模式减少 if else

  •  
  •   twogoods · 2017-03-02 18:16:51 +08:00 · 3993 次点击
    这是一个创建于 2618 天前的主题,其中的信息可能已经有所发展或是发生改变。
    ![]( http://p1.bqimg.com/567571/61a619009daaefa8.jpg)
    我理解的状态模式会把 if else 里的具体逻辑通过状态对象抽象出来,如果有一个场景是读配置文件中的一个值,根据值做不同的逻辑,如果可取的值有 5 个,那么状态模式一定可以减少 if else 的数量吗?
    第 1 条附言  ·  2017-03-02 22:14:46 +08:00
    歪楼了,我的重点在状态模式!
    14 条回复    2017-03-03 17:33:06 +08:00
    KIDJourney
        1
    KIDJourney  
       2017-03-02 19:36:29 +08:00
    count = 1
    if xxxx:
    count += 1
    if xxxx:
    count += 1

    if count != 2:
    return False
    sumhat
        2
    sumhat  
       2017-03-02 19:53:33 +08:00   ❤️ 1
    map: {
    "state1": func1,
    "state2": func2,
    "state3": func3,
    "state4": func4,
    "state5": func5,
    }

    processState(state) {
    func = map[state]
    func()
    }

    完全没有 if/else
    twogoods
        3
    twogoods  
    OP
       2017-03-02 20:07:59 +08:00 via Android
    @sumhat 您这剑走偏锋,没毛病😂
    cafdd239
        4
    cafdd239  
       2017-03-02 20:19:33 +08:00
    @twogoods 这一点也不偏。。。。
    aleen42
        5
    aleen42  
       2017-03-02 20:32:55 +08:00
    Use a lookup table like @sumhat
    aleen42
        6
    aleen42  
       2017-03-02 20:34:17 +08:00   ❤️ 1
    @sumhat 但是直接用数组,访问时会性能更快

    var map = [null, func1, func2, func3, func4, func5];
    ryd994
        7
    ryd994  
       2017-03-03 06:18:18 +08:00   ❤️ 1
    说主题,这里的 if-return 其实不会提高性能
    看起来是少了 if-else ,可也别把编译器当傻子,编译器早就知道优化这种情况了。
    if-return 的用法主要是用在输入验证的时候,可以 if (illegal) return error ,在要验证的内容很多的情况下,可以有效减少嵌套层数,提高代码可读性。和性能没半毛钱关系。

    另外这种情况 C/C++代码用的比较多。
    Python 里面楼上用函数表就是标准做法,一点也不偏,这就是状态模式的一种表达法。如果平时用状态模式考虑问题,这种表达是很自然的。你必须理解一点:程序也是数据。
    C 里面用函数指针也可以实现,不知道为啥不多见。可能因为过程语言本身的习惯,以及函数指针没用起来那么方便。毕竟 C 里面还要自己处理越界,不能依赖 runtime 检查。


    @aleen42 解释型语言就别纠结这种零碎性能了,谁知道 runtime 开销多大。可维护性最重要。不是所有判断条件都是整数的。比如写个 HTTP 后端,完全可以直接用字符串做 method 的选择。
    heiher
        8
    heiher  
       2017-03-03 08:43:39 +08:00
    @ryd994 C 程序之所以减少使用函数指针,我想可能因为是从寄存器跳转的分支预测率是较其它低的。
    zhjits
        9
    zhjits  
       2017-03-03 10:21:12 +08:00
    void branch_1(){ do_something(); }
    void branch_2(){ do_some_other_thing(); }
    void (*selection[])() = { branch_1, branch_2 };
    // ...
    bool condition = a > b;
    (*selection[condition])();

    听说不要用 if ?
    twogoods
        10
    twogoods  
    OP
       2017-03-03 10:36:15 +08:00
    @ryd994 hashtable 的方式看着其实跟 switch 很像呀
    switch(state): {
    case "state1": func1,
    case "state2": func2,
    case "state3": func3,
    case "state4": func4,
    case "state5": func5,
    }
    有 O(1)和 O(n)的差别,当然维护性上看, table 方式会好一点,但具体逻辑抽象成 func1,func2 后,感觉也没那么大了呀
    如果判断条件是整数,字符串也行, switch 本质上只是写法不一样,还是要挨个遍历没减少 if else, table 的方式说减少 if else 能是能接受,总感觉怪。我刚看设计模式,感觉状态模式就是那几个 func1 , func2 的抽象,你总是要根据一个判断条件来确定是哪个 func ,可能我有点钻代码上一代要减少 if else 这个牛角尖了...
    ryd994
        11
    ryd994  
       2017-03-03 14:58:53 +08:00 via Android
    @twogoods 不是 O(n) https://wiki.python.org/moin/TimeComplexity#dict
    你要明白 dict 是带索引结构的,所以可以快
    要避免多层嵌套 if ,否则代码看都看不清。对 Python 尤为重要,毕竟不是所有人都身上带着游标卡尺的。
    还是那句话, if 判断从性能上来讲是无法消除的,但可以消除多层嵌套,提高代码可读性。
    另外,我说可以直接用 string 是这种:
    if method==“ GET ”: do_get ()
    elif method=="POST" do_post()
    ……
    这种用 dict 最合适
    ryd994
        12
    ryd994  
       2017-03-03 15:00:02 +08:00 via Android
    @twogoods 状态模式用适合实现那些可以用状态机简单描述的算法
    bp0
        13
    bp0  
       2017-03-03 15:03:38 +08:00 via Android
    简单的说,使用查表法实现有限状态机。
    padeoe
        14
    padeoe  
       2017-03-03 17:33:06 +08:00
    状态模式是为了解决复杂对象的描述困难的吧,可以减少条件分支。楼主的需求应该是策略模式吧,是无法消灭条件分支的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   779 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:11 · PVG 04:11 · LAX 13:11 · JFK 16:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.