软件中的函数

本文探讨了如何通过优化函数设计,如封装判断逻辑、限制参数数量、遵循单一职责原则、精简辅助代码和优化判空,来提高代码的可读性和复用性。通过实例展示了函数重构和最佳实践,强调了短小、清晰的函数对于软件工程的重要性。
摘要由CSDN通过智能技术生成

把简单的事情做到极致,功到自然成,最终“止于至善”

自从有了面向对象技术之后,很多工程师把精力放在了对象技术上,反而忽视了函数。实际上面向对象和写好函数并不冲突。

写好函数技艺,好的函数能够大大降低阅读代码的困难度,提升代码的可读性。

软件中的函数(方法)

函数是一组代码的集合,是程序中最小的功能模块,一次函数的调用包括接收参数输入,数据处理,返回结果。同一个函数可以被一个或多个函数调用任意次。

在面向对象语言中:方法则是面向对象语言中对函数的叫法。

封装判断

好的函数应该是清晰易懂的,我们从一个简单又实用的函数重构技法说起。如果没有上下文,if和while语句中的布尔逻辑就难以理解。如果把解释条件意图作为函数抽离出来,用函数命名把判断条件的语义显性的表达出来,就能立即提升代码的可读性和可理解性。

例子

判断一个地址是否是小程序地址条件
1.url.scheme 是cmbc
2.url.host 是miniapp

原来代码


NSString *menuUrl = [aMenuItem getUrl];
 NSURL *url = [NSURL URLWithString:menuUrl];
    
    if ([url.scheme isEqualToString:@"cmbc"] && [url.host isEqualToString:@"miniapp"]) {
         [self p_openMiniappFramework:menuUrl nav:aNav];
    }

重构之后代码


   NSString *menuUrl = [aMenuItem getUrl];
  if ([CMBCMiniappUtil isMiniappUrlValid:menuUrl]) {
        [self p_openMiniappFramework:menuUrl nav:aNav];
       
    }

// 判断url是否是小程序url
+ (BOOL)isMiniappUrlValid:(NSString *)miniappUrl {
    
    BOOL result = NO;
    
    NSURL *url = [NSURL URLWithString:miniappUrl];
    
    if ([url.scheme isEqualToString:@"cmbc"] && [url.host isEqualToString:@"miniapp"]) {
        result = YES;
    }
    
    return result;
}

不难发现重构后的代码更容易理解,因为通过封装判断,判断条件的业务语义被显性地表达出来了,代码的可读性自然也好了许多。

函数参数

最理想的参数数量是零,其次一元函数,再次是二元函数,应尽量避免三元函数,有足够特殊的理由才能用三个以上参数。当然也的看具体的场景,在程序中最大忌讳就是教条,有可能两个参数比一个好。

总体上来说参数越少越容易理解,函数也越容易使用和测试,如果函数需要三个以上,那就说明其中一些参数应该封装成类了。
例如要绘制一条直线

可以用如下声明

- (void)makeLine:(CGFloat)startX
          startY:(CGFloat)startY
            endX:(CGFloat)endX
            endY:(CGFloat)endY
X和Y可以看做一组概念被共同传递,我们应该为这一组概念提供一个新的抽象,叫做point,这样将参数对象化之后,参数的个数减少了,表达也更加清晰了。

创建一个新的对象Point

class Point {
 CGFloat x;
 CGFloat y;
}

- (void)makeLine:(Point)start
             end:(Point)end;

短小的函数

函数的第一规则是要短小,第二规则是要更短小。

维护过超长函数折磨的读者应该深有体会,相比于3000行代码的庞然大物,肯定更短小的函数更容易理解和维护。

有时候保持代码的逻辑不变,只是把长方法改成多个短方法,代码的可读性就提高很多。超长方法是典型的代码的“坏味道”,对超长方法的结构化分解是提升代码可读性可读性最有效方式之一。

那么函数的代码的行数多长才合适呢?

这个没有绝对的量化标准,各团队可以有自己的标准,不同开发语言可能会稍有不同,建议一个方法不要超过20行,当把这个规定作为团队代码审查的硬性指标后,发现代码质量得到了显著的改善。

职责单一

按照行数规定函数的长度是定量的做法,但是我更喜欢另一种定性的衡量方法,即一个方法只做一件事,也就数函数职别的单一原则。

遵循单一职责不仅可以提升代码的可读性,还能提升代码的可复用性,因为职责越单一,功能越内聚,就越可能被复用。

通常长方法意味着肯定需要拆分,多要用多个子函数的组合来进行更好的表达,然而短小的函数并不一定就意味着不需要拆分,只要不满足单一职责就需要进一步分解。哪怕分解后的子函数只有一行代码。只要有助于业务语义显性的表达。

精简辅助代码

所谓的辅助代码是程序中必不可少少的代码,但又不是处理业务逻辑的核心代码,比如判空,打印日志,降级和缓存检查等。这些代码往往会在多个函数中重复冗余,减少辅助代码可以让代码更加干净整洁,易于维护。

如果辅助代码太多,会极大地干扰代码的可读性。因此我们应该尽量减少辅助代码对业务代码的干扰,让函数中的代码能直观的体现业务逻辑,而不是让业务代码淹没在辅助代码中,

优化判空

空指针的发明人曾表示对发明空指针的忏悔,说这是一个数十亿的错误,

我们经常会看到这样的代码 if (dec == NULL) return ;的代码,其本身并没有什么问题,也是为了代码的健壮性。只是这样的判空代码多了,会干扰阅读代码的流畅性。

看下面的简单实例有时候我们为了代码的健壮性,在访问值时会对其进行明确的检查

if(user!=null){
    Address address = user.getAddress();
    if(address!=null){
        String province = address.getProvince();
    }
}


可以看到这样的代码多么复杂

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值