当某函数内代码行数过长时是否有必要对其进行拆分? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
XiaST
V2EX    程序员

当某函数内代码行数过长时是否有必要对其进行拆分?

  •  
  •   XiaST 2015-12-17 14:23:33 +08:00 5557 次点击
    这是一个创建于 3588 天前的主题,其中的信息可能已经有所发展或是发生改变。

    函数代码的行数已经超过了 400 行,也可以将其划分成多个细化的功能块,但是这些功能块都只会在这个函数中被用到,而且在函数内功能块开始的地方都有了相应的注释桌面(也就是说一般不会影响代码阅读),那么在这样的情况下还有必要对这些功能块拆分成多个函数吗?

    28 条回复    2016-01-12 23:17:10 +08:00
    doublleft
        1
    doublleft  
       2015-12-17 14:55:55 +08:00
    首先你能思考函数过长这个问题很棒。
    你说你要拆分函数的目的,我列两个场景,你看看哪个更贴切一些:

    1. 这为了代码可读性,为了别人看到的时候啧啧称赞,为了让人类看起来更优雅些。但实际这个函数完全隔离,根本不会有其他代码用到。

    2. 用起来可以满足其他场景,用起来满足抽象继承多态复用…,用起来更爽些。但实际这个函数完全隔离,根本不会有其他代码用到。
    amaranthf
        2
    amaranthf  
       2015-12-17 14:58:04 +08:00
    函数简短的好处,一个是易于阅读,另外非常重要的一点是,易于维护……比如别人需要去动你这 400 行代码中的某几行,其中引用了 5 个局部变量,每个变量其他被引用的位置都贯穿整个函数始终,那这个人要改起来就必须得从头到尾的去寻找这些变量是怎么被引用的,万一修改了值,会不会影响到前后的功能等等。而如果只需要改一个 30 行的函数,那只需要关注函数的输入输出,压力就会小很多。
    amaranthf
        3
    amaranthf  
       2015-12-17 15:02:06 +08:00
    至于复用,而且在写一个函数的时候就考虑到其他各种场景的复用,这个对程序员本身的要求就非常高了,绝大部分程序员所做的事情是,自认为从中拆出了某些可复用的功能,做成一个新的函数,而当另外写代码去“复用”时,发现并不能满足新场景的需求,于是又开始对原始函数缝缝补补……所以如果经验尚浅,不必对复用对自己提出太高的要求,实际需要的时候再考虑即可。
    XiaST
        4
    XiaST  
    OP
       2015-12-17 15:58:08 +08:00
    @doublleft 应该算是第一种吧。。。平常写代码的时候都会尽量把函数代码行数控制在三四十行内,不过这次由于写的东西对速度会有点要求,细分成多个函数担心会影响效率什么的。。。不过现在阅读起来是有点痛苦,所以就在纠结到底是写在同一个函数里好还是细分开来比较好。。。
    pathletboy
        5
    pathletboy  
       2015-12-17 16:01:01 +08:00
    @XiaST 有些语言有内联机制,编译器自动会优化,不用担心调用函数上的开销,当然 c/c++你可以使用关键词 inline ,建议编译器内联。
    XiaST
        6
    XiaST  
    OP
       2015-12-17 16:05:10 +08:00
    @amaranthf 维护的话现在的 IDE 功能都已经比较强大了,找个变量的声明和调用的位置应该问题不大。。。至于修改值影响后面功能的问题= =感觉就算是用函数封装后也没法杜绝这个问题来着,该影响的还是有影响,或者如果有实际的实例的话希望能举个例子。。。然后复用的况我这里应该是没有体现出来吧。。。每个功能块就同一个地方会被使用到
    harry890829
        7
    harry890829  
       2015-12-17 16:05:31 +08:00
    我觉得代码拆分主要还是函数的复用,这个非常重要
    XiaST
        8
    XiaST  
    OP
       2015-12-17 16:27:24 +08:00
    @pathletboy 我使用的是 Java 。。。然后据我所知 Java 应该没有做类似的优化。。。
    pathletboy
        9
    pathletboy  
       2015-12-17 16:54:37 +08:00
    @XiaST 用 java 就不要太讲究运行效率了,追求运行效率就不会用 java 了是不?代码是给人看的,只是顺便给机器运行,所以代码的可读性应该放在第一位。
    minsheng
        10
    minsheng  
       2015-12-17 18:21:01 +08:00 via iPhone
    首先,性能大多数情况下都应该不是个大问题,要是这么简单的情况编译器都处理不了,我建议楼主转行读 PhD 。

    然后,拆函数大概有两个好处,一是代码复用,这个大家都很清楚。二是可以用作文档选择有意义的子函数名不过这个功能可以用注释代替。

    楼主的一个担心看来似乎是污染全局空间,但如果楼主用的语言不像 Haskell 那样有 where ,楼主可以定义几个 lambda ,这也是等价的。

    最后,写成多个函数,如果不滥用 capturing ,可以减少子函数之间共享的状态,对未来维护应该是方便的。
    exch4nge
        11
    exch4nge  
       2015-12-17 18:50:30 +08:00 via iPhone
    如果有代码规范规定这方面的,就按规范来。没有的话根据自己喜好吧。很多大型项目的源代码里一个函数几千行的也挺常见的。
    h4de5
        12
    h4de5  
       2015-12-17 19:30:45 +08:00
    看 Android 源码,里面经常一个函数上千行代码.
    quix
        13
    quix  
       2015-12-17 19:34:37 +08:00
    除了楼上提到的, 函数短小另外有一个好处就是方便单元测试, 每个函数的功能和目的单一, 就容易测试.
    lightening
        14
    lightening  
       2015-12-17 19:38:35 +08:00 via iPhone
    拆分大函数其实有个很重要的功能就是告诉维护者:这块功能相对独立,需要这几个参数。里面具体实现放心改,不会搞坏后面的那 200 行代码。

    从这个意义上说,当然是很有好处的。

    事实上,我们公司的内部标准说方法最好不要超过 5 行。当然我们用 Ruby, 代码简短的多。
    awfe
        15
    awfe  
       2015-12-17 19:58:40 +08:00
    @XiaST Java 会在运行期进行 inline 的
    Feiox
        16
    Feiox  
       2015-12-17 20:00:29 +08:00
    @XiaST 不要小看 JVM 。。。真心的。
    vietor
        17
    vietor  
       2015-12-17 20:11:38 +08:00 via Android
    看语言,以不拆为主
    AbrahamGreyson
        18
    AbrahamGreyson  
       2015-12-18 04:01:31 +08:00
    拆分从来都不是看长短,看职责是否单一,一个函数是否知道太多内容,是否做到关注分离了,是否易于单元测试。废话就不说了。
    miao1007
        19
    miao1007  
       2015-12-18 05:41:06 +08:00
    王垠大神曾经说过,以 38 行(正好是 IDE 中一页的高度)为一个函数。
    br00k
        20
    br00k  
       2015-12-18 08:58:11 +08:00 via Android
    @miao1007 不够肿么办,回车补全么 XD
    orderc
        21
    orderc  
       2015-12-18 13:35:54 +08:00
    看一下<代码简洁之道>和<重构改善代码的既有设计>就可以做出判断了。
    SmiteChow
        22
    SmiteChow  
       2015-12-18 15:19:32 +08:00
    有必要的,最多一屏高度。最好半屏高度。
    shaoqiang
        23
    shaoqiang  
       2015-12-18 18:03:08 +08:00
    复用只是一个原因。
    不能因为不能复用就拆分函数了。
    还有个目的就是易于阅读代码啊。

    所以,不能复用的时候,如果语言支持匿名函数,就用匿名函数,否则就拆出来,不会害你害别人的。
    shaoqiang
        24
    shaoqiang  
       2015-12-18 18:04:28 +08:00
    擦,上面第二句写反了(应该是:不能因为不能复用就不拆分函数 )。但貌似还不能编辑。
    XiaST
        25
    XiaST  
    OP
       2015-12-20 11:12:06 +08:00
    @awfe 真的有吗。。。查了半天的资料,只看到在指定为 final 的时候才会有展开。。。而且貌似效果不好。。。如果有资料的话希望能发一下。。。
    awfe
        26
    awfe  
       2015-12-20 13:25:50 +08:00
    XiaST
        27
    XiaST  
    OP
       2015-12-21 14:55:12 +08:00
    @awfe 学习了
    MiskoLee
        28
    MiskoLee  
       2016-01-12 23:17:10 +08:00
    @miao1007 那该换块屏幕了,我的屏幕可以显示 100 行+啊

    首先,多余的函数调用会增加额外的 call 时间。除非可以做到零抽象。比如用宏来拆分业务,其实我是喜欢用宏来写代码生成器的。

    如果,是 Web 应用,那么函数 call 时间之类的时间可以忽略,爱写多少层写多少层。毕竟撑死系统的都是烂 SQL 。


    函数写的短小是政治正确的,然而并不具备多大的现实意义。我见过太多知名代码的函数太长了,一个 C 文件数万行代码的比比皆是。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3297 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 11:48 PVG 19:48 LAX 04:48 JFK 07:48
    Do have faith in what you're doing.
    ubao 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