通过状态模式减少 if else - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
twogoods
V2EX    程序员

通过状态模式减少 if else

  •  
  •   twogoods 2017-03-02 18:16:51 +08:00 4559 次点击
    这是一个创建于 3221 天前的主题,其中的信息可能已经有所发展或是发生改变。
    ![]( 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     Solana     2646 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 12:03 PVG 20:03 LAX 04:03 JFK 07:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86