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