自从在Swift中出现guard语句以来,已经有很多讨论。说真的,guard确实简化了代码,提高了代码的可读性,但它是万能的吗?小函数关于函数大小的讨论也很多。显然,函数体要短,而且越短越好。没有人愿意阅读、理解或重构大型函数。但是一个函数应该有多大呢?函数的第一个标准是——短。次要标准是——更短。---Robert`C`Martin更具体地说,Martin认为函数的长度应该少于六行,并且绝不能大于十行。规则很简单,但效果显着,你可以看到代码立即变得更容易理解。以前,你需要记住一个有30行代码、几级缩进和几个中间变量的函数。现在你只需要记住十个名字清楚的函数就可以了。SingleResponsibility单一职责也说了很久。这条规则不仅适用于对象,也适用于函数。显然,每个函数应该只做一件事,但是人们打破这个规则一两次,主要是因为看起来函数的大小。如果将一个30行的函数重构为10个3行的函数,那么在函数级别会自动遵循单一职责规则。单级抽象人们很少谈论函数的单级抽象。它是一种有助于编写单一职责功能的工具。什么是单级抽象?简单地说,具有高度抽象的代码,例如控制进程的代码,不应混入小细节,例如变量自增或布尔值检查。举个栗子。以下示例摘自《TheSwiftProgrammingLanguage》一书。structItem{varprice:Intvarcount:Int}enumVendingMachineError:ErrorType{caseInvalidSelectioncaseInsufficientFunds(coinsNeeded:Int)caseOutOfStock}classVendingMachine{varinventory=["CandyBar":Item(price:12,count:7),"Chips":Item(price:10,count:4),"Pretzels":Item(price:7,count:11)]varcoinsDeposited=0funcdispense(snack:String){print("Dispensing\(snack)")}funcvend(itemNamedname:String)throws{guardvaritem=inventory[name]else{throwVendingMachineError.InvalidSelection}guarditem.count>0else{throwVendingMachineError.OutOfStock}guarditem.price<=coinsDepositedelse{throwVendingMachineError.InsufficientFunds(coinsNeeded:item.price-coinsDeposited)}coinsDeposited---coinsDeposited--计数库存[名称]=itemdispense(name)}}当然,vend(itemNamed:)只是使用gaurd语句的一个示例,但您会经常在生产代码中看到类似的函数。这个函数有上面提到的三个问题:它很长,有16行,很多部分都是用空行分隔的。它做了几件事:通过名称获取产品,验证参数的合法性,然后是销售产品的逻辑。它有几个抽象层次。顶级销售流程隐藏在更精细的细节中,例如布尔值验证、特殊常量的使用、数学运算等。重构后这个函数是什么样子的?funcvend(itemNamedname:String)throws{letitem=tryvalidatedItemNamed(name)reduceDepositedCoinsBy(item.price)removeFromInventory(item,name:name)dispense(name)}privatefuncvalidatedItemNamed(name:String)抛出->Item{letitem=tryitemNamed(name)tryvalidate(item)returnitem}privatefuncreduceDepositedCoinsBy(price:Int){coinsDeposited-=price}privatefuncremoveFromInventory(varitem:Item,name:String){--item.countinventory[name]=item}privatefuncitemNamed(name:String)抛出->项目{ifletitem=inventory[name]{returnitem}else{throwVendingMachineError.InvalidSelection}}privatefuncvalidate(item:Item)throws{tryvalidateCount(item.count)tryvalidatePrice(item.price)}privatefuncvalid(idateCountcount:Int)throws{ifcount==0{throwVendingMachineError.OutOfStock}}privatefuncvalidatePrice(price:Int)throws{ifcoinsDeposited
