热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

函数要尽量设计得短小精悍

“设计良好的函数往往比较小,而过大函数的设计往往一塌糊涂,或者存在很大的优化空间。”也许你认为讨论函数的大小没有必要,原因是函数设计的本质是内聚,它的大小只是它的表现形式。而上面的原因有必要让我们讨论一下函数的大小问题。我对函数的核心思路:我提出代码最小处理单元的概念:一个基本操作(赋值,比较等),一个函数调用(包括调

“设计良好的函数往往比较小,而过大函数的设计往往一塌糊涂,或者存在很大的优化空间。”

也许你认为讨论函数的大小没有必要,原因是函数设计的本质是内聚,它的大小只是它的表现形式。而上面的原因有必要让我们讨论一下函数的大小问题。

我对函数的核心思路:我提出代码最小处理单元的概念:一个基本操作(赋值,比较等),一个函数调用(包括调用后判断返回值进行判断)都看成一个最小处理单元。那么,一个函数,最小处理单元合理的个数范围在7以内。如果超过了7,你就要考虑把他们拆分成多个函数了(为什么是7?人同时能够处理的信息不超过7个)。

最小数目没有限制,即便是只有1个,也有存在的必要。

在下面的情况下我会将函数拆分为更小的函数:

  1. 一眼不能够看到函数所有的代码。如果函数过长,无法一眼看到一个函数所有的代码,我会毫不犹豫的拆分。我不想让读者去翻屏,也不想让读者前顾后盼,顾此失彼。漂亮的函数应该让读者一眼就知道他在做什么以及怎么做的。
  2. 局部变量过多。如果局部变量超过七个,我会考虑拆分函数。变量过多意味着我要记录太多的状态,这会加重我大脑的负担,同时要考虑太多的东西。这也同时意味着我可能没有对函数功能进行深入的思考。
  3. 太多的缩进。太多的缩进意味着太多的嵌套,要么是循环,要么是判断,都会导致复杂的逻辑。
  4. 如果你在使用ctrl+c和ctrl+v。那你写的代码不够拽(DRY,Don't Repeat Yourself)。这个时候,你要把你复制的部分拆分为新的函数。
  5. 不处于同一抽象层次。举例,有一个初始化函数,需要初始化配置数据,套接字,数据库连接,通道状态。
void init()  
{  
	config_init();  
	socket_init();  
	db_init();  
	int i = 0;  
	for (i = 0;i 
	
	

上个函数中对所有通道的初始化一块代码就和其他的不处于一个抽象层次,我们应该将它封装起来:

void chn_init()  
{  
	int i = 0;  
	for (i = 0;i 
	
	

函数最小可以有多小,它存在的意义

我见过的最优秀的函数:

int max(int a, intb)  
{  
	return a > b?a:b;  
}  

这个函数很小,只有一行,但是他存在的意义在于:在函数的调用点,我们一眼就知道是获取a和b中的最大值,而不是分析a > b?a:b的逻辑。这样可以节省程序员的脑力成本,从而达到一个目的:漂亮的函数应该让读者一眼就知道他在做什么以及怎么做的。

小函数的最大障碍:性能

对于程序员新手,小函数的最大障碍在于没有经验体会不到小函数的优势,没有经验拆分大函数为更小的函数。

对于有一定经验的程序员,小函数的最大障碍也许是对性能的忧虑。

对于性能,切记,不要过早优化。我们一般认为的程序的瓶颈,一般并不是程序的瓶颈:我们需要工具来确定真正的瓶颈所在,20%的代码耗费了80%的性能,优化之前首先要找到那20%的代码。函数调用会产生资源和性能的损耗,但是这是不是程序的性能瓶颈?消耗的性能占总体的性能百分比为多少?这一切在代码编写时并不清楚,所以,我的观点是宁可选择简短的函数来获得清晰简单的设计,以便在项目后期能够更快,更好的进行性能优化。

很多人都在质疑我上面列举的max函数的实例,如果说他在运行期间调用次数不大,则对性能的影响基本可以忽略,而获得的可读性,清晰性这极具价值;反过来,如果他的调用次数是否庞大,以致成为了性能的瓶颈,则完全可以在程序编写完成后,很快的用其他的方法优化。程序的瓶颈不会很多。

关于函数调用产生的性能消耗,我会抽时间测试一下,看到底占用多少。

最后的建议:在对新员工培训的过程中,发现程序员新手一般对函数的大小不够敏感。所以,我建议你可以多尝试编写10行左右(甚至更小)的函数,慢慢你会发现小函数原来具有大威力。

本文地址:http://www.nowamagic.net/librarys/veda/detail/90,欢迎访问原出处。


推荐阅读
  • 本文详细介绍了在XAMPP环境中如何修改Apache和MySQL的默认端口号,并确保WordPress能够正常访问。同时,提供了针对Go语言社区和Golang开发者的相关建议。 ... [详细]
  • Java项目分层架构设计与实践
    本文探讨了Java项目中应用分层的最佳实践,不仅介绍了常见的三层架构(Controller、Service、DAO),还深入分析了各层的职责划分及优化建议。通过合理的分层设计,可以提高代码的可维护性、扩展性和团队协作效率。 ... [详细]
  • Linux环境下进程间通信:深入解析信号机制
    本文详细探讨了Linux系统中信号的生命周期,从信号生成到处理函数执行完毕的全过程,并介绍了信号编程中的注意事项和常见应用实例。通过分析信号在进程中的注册、注销及处理过程,帮助读者理解如何高效利用信号进行进程间通信。 ... [详细]
  • 2004年春节,作者与父亲讨论了未来的职业规划,并决定尝试创业开设家教培训班。然而,创业过程中的种种困难和挑战最终导致了项目的失败。 ... [详细]
  • 设计模式在软件开发中被广泛应用,但如果不当使用,可能会导致系统复杂性增加。例如,过度添加类可能导致类图难以理解,代码跟踪变得复杂。本文探讨如何在使用设计模式时保持系统的简洁和高效。 ... [详细]
  • Go语言实现经典排序算法:归并排序
    本文介绍如何使用Go语言实现经典的归并排序算法,探讨其原理、代码实现及性能特点。适合Golang开发者和编程爱好者。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • SpringMVC RestTemplate的几种请求调用(转)
    SpringMVCRestTemplate的几种请求调用(转),Go语言社区,Golang程序员人脉社 ... [详细]
  • 程序员如何优雅应对35岁职业转型?这里有深度解析
    本文探讨了程序员在职业生涯中如何通过不断学习和技能提升,优雅地应对35岁左右的职业转型挑战。我们将深入分析当前热门技术趋势,并提供实用的学习路径。 ... [详细]
  • 程序员版情书:王思聪的编程式告白
    当程序员用代码表达爱意,会产生怎样的化学反应?一起来看看这封充满技术感的情书,网友笑称这才是真爱! ... [详细]
  • docker镜像重启_docker怎么启动镜像dock ... [详细]
  • Java中的基本数据类型与包装类解析
    本文探讨了Java编程语言中的8种基本数据类型及其对应的包装类。通过分析这些数据类型的特性和使用场景,以及自动拆装箱机制的实现原理,帮助开发者更好地理解和应用这些概念。 ... [详细]
  • GoCV入门指南:配置与基础应用
    本文详细介绍了GoCV的安装配置及基本使用方法,包括如何打开摄像头、图片和视频文件。适合Golang开发者快速上手。 ... [详细]
  • 远程过程调用(RPC)是一种允许客户端通过网络请求服务器执行特定功能的技术。它简化了分布式系统的交互,使开发者可以像调用本地函数一样调用远程服务,并获得返回结果。本文将深入探讨RPC的工作原理、发展历程及其在现代技术中的应用。 ... [详细]
  • Java多重继承的替代方案及设计考量
    本文探讨了Java为何不支持多重继承,并深入分析了其背后的原理和替代方案。通过理解Java的设计哲学,开发者可以更好地利用接口和其他特性来实现复杂的类结构。 ... [详细]
author-avatar
皇家冷情绪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有