
1 jox Dec 5, 2014 如果A,B,C只在dosomething里会用到,没必要拆分,在 不同的功能块前面使用注释区分也一样,性能上也有一点点优势,免去了函数调用的开销,如果dosomething很长,无所谓,现在的IDE都带代码折叠功能,不需要编辑的区块折叠起来就行 不过不需要拆分的情况不多见,一般函数之间都是互相调来调去的,都需要把重复的代码弄成个函数 |
2 akira Dec 5, 2014 1. 一个函数尽量只做一个事 2.一个函数的长度要适中。 至于你的理由, 1/2可以把函数做成局部函数, 3 doA/doB/doC 可以视为大纲,是有助于代码阅读的。 4 确实是有可能会有这种情况,要具体案例具体分析了 |
3 binux Dec 5, 2014 首先2不成立,函数输入输出的重新设计,正是梳理函数功能的过程,让函数只能看到它需要的变量。 3也不成立,函数单独拆出的原则是函数是能独立工作的,而经过2,使得接口更清晰,会让它更容易理解。而且拆出去之后loc不变,实际阅读量不变。 4函数拆分的原则就是功能是独立的,拆出去的函数如果功能不独立,请考虑你拆分方式是否有问题?! 由2-4点得,独立成函数不是意义不大的,不是过度设计。 |
4 yeqiu Dec 5, 2014 别的语言我不懂啊,对于oo的语言,例如c#,如果拆分的话,因为方法树的存在会增加内存消耗。 |
5 chmlai Dec 5, 2014 这样拆分一下谈不上什么"过度设计" |
6 chmlai Dec 5, 2014 另外只是那点函数调用就别谈什么性能不性能了吧, 又不是递归 |
7 hh3755 Dec 5, 2014 虽然我也是个菜鸟,我觉得还是应该拆出来,因为函数太大,实在不好维护的,别人理解起来也会有点费劲。 理由: 1. 对于参数的问题。参数可以全部封装到一个对象中去,或者直接丢到一个KEY,VALUE的结构中。改变参数也不会改变代码,关于参数本身的校验全部耦合到参数对象中去。 2. 独立后的每个子函数职责就更清晰,可以在函数命名时就明确其作用,比如doCheck,doProcess,releaseResouce. 3. 当然不太清楚你的场景啊,瞎猜,有的时候拆着着,就会发现,原来有些东西可以放在一起,哈哈。 |
8 JonyOang Dec 5, 2014 逻辑分割,单一目的,长度适中,支持分割,哈 |
9 staticor Dec 5, 2014 可拆,或者说如果能拆就方便拆。 主要是方便以后的扩展设计,对一个函数的调用修改可在调用时再装饰 |
10 repus911 Dec 5, 2014 应该按照实际情况来考虑,一个爬虫和一个系统毕竟不一样,但是…… 1. 过度设计你妹啊 300行的函数完全不能忍啊 2. 你改原函数也要做的事情,而且300行代码还可能带暗雷 3. 你看一个函数的名字,参数,输出,就可以明明白这个函数的功能了 2/4 万一,一旦 你这算不算过度设计 4. 拆开主要是帮你理清逻辑的,你会发现自己改的更快了 300行的代码老兄你真的能忍 我是写python的 |
11 88250 Dec 5, 2014 等纠结完这些,别人同样特性的产品已经上线了.... |
12 jiang42 Dec 5, 2014 肯定拆 理由1:你不会知道以后会不会在其它地方用到A,B,C的。。。 理由2:IDE自带重构-。- 理由3:如果需要读A,B,C只能说你A,B,C有问题,A,B,C的名字就应该描述其作用 理由4:不能拆开你提什么分拆函数?实际上一般逻辑都是能拆开的,拆不开说明水平不够。至于修改doSomething,考虑一下,如果只有A出现问题,则去A子函数修改就好了,不拆分的话你需要理清楚修改A是否会影响B,C @yeqiu 99%的性能问题都是程序员的意淫。与其死扣细节,不如学好算法和数据结构。 |
13 jerry2014 Dec 5, 2014 先订好一套规则,大家都根据这个规则来写。 |
14 standin000 Dec 5, 2014 无参数调用,可以试试inline。 有参数调用首先要考虑参数本身的意义。如果参数固定,就建议用子函数,要改什么就在子函数里改就可以了。 |
15 lincanbin Dec 5, 2014 我不会,我只封装会重复使用的代码。 现在只用一次,以后用不用,那是以后的事,现在就封装就是过度设计了。 |
16 matrix67 Dec 5, 2014 via Android 楼主头像和我我好像像 |
18 sampeng Dec 5, 2014 我会,理由。。 3个月后,300行的代码,以我的记忆而言,肯定忘得干干净净。。写注释,怎么也不会比小函数简单明了。 |
19 sampeng Dec 5, 2014 补充一句,超过200行代码,不管多简单明了,不管是不是我写的,我都会直接上手自己重构一下。。因为没耐心去看 |
20 ipconfiger Dec 5, 2014 如果第一条成立就没有必要拆分。拆分狂魔恨不得一个函数只有一行代码,BT得过分 |
21 goool Dec 5, 2014 程序里偶尔出现长函数是可以理解的,参数检查、资源申请、错误处理、对象转换等等,七七八八“不干正事”但又不能没有的周边代码加起来自然就长了。 但是书上说的总是对的:别写长函数;但是,但是实际代码总是有妥协的。 总的来说,别真的太长,长函数别太多,一两个没事,再多就有问题了。 |
22 acros Dec 5, 2014 我很可能会拆。 问题在第一句: “do A/B/C中的内容不会被其他函数复用,仅仅在doSomething中被用到” 这个情况我不太敢肯定。需求永远会变的,即使看起来只被一个地方调用的函数,实际都有很高的概率被复用,先做好这个API比较容易被别人引用。如果写在一个大函数里面,可能自己都想不起来了。 |
24 Her0 Dec 5, 2014 我不会拆。 第一:楼主明确说了拆出来的ABC也没有其他函数会调用它们,所以拆了冗余 第二:拆出来需要每个函数都要重新写一遍参数,万一以后要改,代价就大了 |
25 ipconfiger Dec 5, 2014 @acros 不太感肯定的时候就先拆了再说是典型的过度设计的表现,首先你怎么知道你的拆分就是完全正确的?第二万一拆分后以后要复用的点不一样,那么你要怎么改? 借用楼上很多主张拆的同学说的观点,有重构工具了拆分函数很方便,yes,这就是不拆的理由,将来万一需要拆分,有重构工具也就是很简单就可以拆出去了。 现代IDE有folding功能可以把大函数的几个功能块折叠了,看不是问题 再次重申,提前优化是万恶之源 |
26 anerevol Dec 5, 2014 通常情况我是拆的,除非ABC相关非常密切。 忽然忘记300行是啥概念了,翻了翻自己的代码通常一个类200~400行。 |
27 dorentus Dec 5, 2014 via iPhone 如果没有其他原因的话,我不会选择去动这个函数。 |
28 deljuven Dec 5, 2014 via Android 各个部分加注释加log,然后不动。。。 |
29 spacewander OP @binux 你说得也对,拆分之后适合更加细化去考虑每个子函数的职责。 有一点我没有提出来……doA和doB和doC间传递(依赖)的参数过多,有4个deque和3个map。这样的参数依赖使得复用是基本不可能的……而且万一要从deque改成list,或者map改成unordered_map,函数参数就要大改了。 而且现在不拆分,除了相对难以理解,并不会带来什么问题。而即使拆分了,也不会带来什么好处,因为从业务逻辑或者代码间的依赖而言,复用是无需考虑的事。等到将来有需要,再进行拆分,也不算迟。 |
30 williamx Dec 5, 2014 对 lz 来说,这其实是一个非常主观的问题,而且自己其实已经有答案了,别人再多说什么也没有意义。我能说的只剩下: 如果是我来写的话,看着不爽就拆,而不是考虑是不是被复用! |
31 spacewander OP @binux 你说得对,分拆成各个函数后可以专注于每个函数的职责。 我忘了提到一点……doA/doB/doC之间依赖非常重,是4个deque和3个map。 第一个获取数据,填充这几个容器 第二个根据前面获取的数据,再进行粗加工 最后一个根据前面两步的结果再进行细加工 因为相关逻辑的关系,基本上复用不会有的……就算将来要复用,再分拆也不迟。 总之,现在不拆,麻烦就是程序逻辑相对难懂,但是拆了,就变得不那么灵活了。(这三个之间的耦合太重了,拆开比较困难) 另外,如果要把deque改成list,把map改成unordered_map,相关的函数参数上的修改会令人抓狂的,而如果不拆,工作量会小很多。 |
32 spacewander OP |
33 spacewander OP 网络问题……我还以为第一次回复不成功了呢…… |
34 layout Dec 5, 2014 支持拆分: 1.函数过长维护难度变大,有可能变量定义在函数开头,底部还在使用,出错几率增加,同时阅读难度增加; 2.职责划分,这三块虽然只在一个函数中被调用,但是可以将职责相当的内容封装在一起,便于理解和改动;现在不调用不代表将来不调用; 3.便于测试,针对一个300行的函数写单元测试....我会奔溃,但是针对3个100行的函数,测试要考虑的点会少一些; 这个世界是有很多个简单组成的复杂体,而不是一个大而冗长的对象。任何东西大了就会分解成为小的,便于我们的理解和重用。这也是为什么出现了组件化、对象化、函数化等设计方法。 |
35 icylogic Dec 5, 2014 就算题主已经有预设立场也不妨碍我们继续讨论嘛 我目前觉得拆分函数, 主要就两个目的 一个是重构成正交函数, 从而方便复用和增强可读性. 如果你觉得这是一段线性的, 连续的逻辑, 而不存在分支或者更复杂结构的逻辑, 那这个理由就没有了 二是为了测试而调整, 我是这样想的, 比如一个流程是 A->B->C, 各有5种可能的输入会产生 bug, 为了让这些情况都被覆盖到, 你**可能**就要设计一大坨测试用例(取决于ABC之间的关系, A 也许永远不会产生会导致 B 出现 bug 的输出, 那就只需要照顾到 A, 但这是隐患, 如果你将来不记得了, 把 A 改成 A', 可能就会出问题), 但是拆成ABC, 那你每个测试都写很少的用例就可以覆盖到全部情况了 |
36 luoweihua7sync Dec 5, 2014 同意二楼,单一原则,应该拆分。 我个人认为,代码有2个主要作用: 1,运行,不能跑的代码什么都不是 2,可读(可维护)。 |
37 ryd994 Dec 5, 2014 如果确认不可能复用,那不拆也可,但是用多行空行隔开,还有注释,保持清晰。 |
38 chmlai Dec 5, 2014 分开来写成方法不一定非为了复用, 很多时候是分离以下复杂度. |
39 ariestiger Dec 5, 2014 当然得拆了。 尽量减少方法行数,超过 50 行的方法, 如果不是多个循环嵌套或者 if 来 else 去, 那说明这方法里已经干了不少事了, 方法体短一点, 方法名参数名有意义一点,节省别人的思考时间, 也让将来自己回头看的时候脑子少转个弯。 为什么设计,开发,面向用户的时候都说“不要让我思考”, 等到写代码需要和同事交流,需要和未来的自己交流的时候, 就不这么考虑呢? |
40 JamesRuan Dec 6, 2014 via Android 拆!300行一个函数不能忍! 函数不仅仅是为了复用而写的,更是为了合理划分功能,提高可读性和可测试性。 一个几百行的函数,十多个只用一两次的局部变量好,还是几个几十行的函数,每个里个位数的局部变量好? 可读性,可测试性,可维护性哪个都是后者高。 损失呢?除了内存使用和调用时间都是O(1),增加的代价可以忽略不计。 |
41 jedihy Dec 6, 2014 可以试试 inline 或者宏定义 |
42 barbery Dec 6, 2014 必须拆。。。 |
43 cvrock Dec 6, 2014 unsigned DoAct(ACT_TYPE type) { unsigned ret = 0; switch(type) { case TYPE_A: ret = DoActA(); break; case TYPE_B: ret = DoActB(); break; default: ret = -1; } //log、assert什么的统一放这里 LOG("Do act xxx returns xx.\n"); return ret; } 我喜欢这样。 |
44 ryanking8215 Dec 6, 2014 via iPad 我会拆的,初始化的时候这种情况很多,拆开来会比较eye candy。 |