余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

关于Swift中是否应该弃用guard的思考(孩子是否应该做家务英语作文)

xiyangw 2022-12-03 12:43 15 浏览 0 评论

Alexei Kuznetsov关于《从你的代码中删除guard)》一文在国外iOS开发者群中引起了许多讨论。Kuznetsov指出支持他这篇文章的理论依据主要来自于Robert C. Martin,这位世界顶级软件开发大师提出:代码必须精简。即关于函数存在两条规则,第一条:函数应该保持精简;第二条:没有最精简,只有更精简。Alexei Kuznetsov表示应将Martin的理论应用在今后的Swift开发中。

对此,Erica Sadun撰写了文章《关于guard的另一种观点》,来反驳Kuznetsov提出的观点。而本文作者DAVID OWENS II也同样给出了自己的想法。

关于Swift中是否应该弃用guard的思考(孩子是否应该做家务英语作文)

Alexei Kuznetsov的《从你的代码中删除guard》一文让我不禁想起那些很多人信以为真的编程谣言。但在我看来,并不存在所谓的“标准编程方法”,必须具体问题具体分析后,再选择一条合适的路走下去。

在一些路的终点,风景总是美好的,尽管多多少少会有不完美,而且最终抵达的目的地不见得有最美的风景。对于开发者而言,编程环境很重要,而且要避免走一些弯路——通过上面的博文多少可以借鉴过来人的经验。

那么,哪些弯路(即编程禁忌)要尽力避开呢?

  1. 认为函数应为6-10行;
  2. 认为函数的“单一职责”就是做好一件事足矣。

第1条随意定义了代码的质量和复杂度,并不保证能解决问题;还妄下定论称代码越短越好——而事实是,代码越短就越复杂。而我觉得代码干净利落比长短要重要得多。

以下是Robert C. Martin对于代码长度的看法:

The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. 函数的第一原则——小;第二原则——更小。

下面这段话总结得更好:

Functions should be as small as possible to do there job, but no smaller than that. 函数应做到小,但刚刚好才是最好。

很多人误以为“单一职责”就是搞定一个action那么简单,忍不住过早进行代码重构——一会儿我会举一些博文中的例子。

一个函数执行一个任务时,通常要经过多个步骤——鉴于我们需要vend函数来避免复制逻辑,这一点应该很好理解。

过早重构

现在来看看这篇博文中的内容。以下是来自Apple示例的Swift代码:

struct Item {
    var price: Int
    var count: Int
}

enum VendingMachineError: ErrorType {
    case InvalidSelection
    case InsufficientFunds(coinsNeeded: Int)
    case OutOfStock
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]

    var coinsDeposited = 0

    func dispense(snack: String) {
        print("Dispensing \(snack)")
    }

    func vend(itemNamed name: String) throws {
        guard var item = inventory[name] else {
 throw VendingMachineError.InvalidSelection
        }

        guard item.count > 0 else {
 throw VendingMachineError.OutOfStock
        }

        guard item.price <= coinsDeposited else {
 throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price
        --item.count
        inventory[name] = item
        dispense(name)
    }
}

这是从博文中摘出的重构版本:

func vend(itemNamed name: String) throws {
    let item = try validatedItemNamed(name)
    reduceDepositedCoinsBy(item.price)
    removeFromInventory(item, name: name)
    dispense(name)
}

private func validatedItemNamed(name: String) throws -> Item {
    let item = try itemNamed(name)
    try validate(item)
    return item
}

private func reduceDepositedCoinsBy(price: Int) {
    coinsDeposited -= price
}

private func removeFromInventory(var item: Item, name: String) {
    --item.count
    inventory[name] = item
}

private func itemNamed(name: String) throws -> Item {
    if let item = inventory[name] {
        return item
    } else {
        throw VendingMachineError.InvalidSelection
    }
}

private func validate(item: Item) throws {
    try validateCount(item.count)
    try validatePrice(item.price)
}

private func validateCount(count: Int) throws {
    if count == 0 {
        throw VendingMachineError.OutOfStock
    }
}

private func validatePrice(price: Int) throws {
    if coinsDeposited < price {
        throw VendingMachineError.InsufficientFunds(coinsNeeded: price - coinsDeposited)
    }
}

分解后进行分析:

vend(itemNamed name: String) throws

博文作者认为重构版本更好。但要注意:首先,函数职责从头到尾都是一样的,所以使用API也不会引起任何改变。了解这一点至关重要,因为重构就是为了拆分不属于一类的功能。

private func validatedItemNamed(name: String) throws -> Item

刚开始我并不清楚这是干嘛用的,后来仔细分析了其调用的代码,发现它主要是为了:

  1. 确保将条目(item)添加到字典里;
  2. 条目的数量不得为零;
  3. 存入的硬币数量不小于条目的价格。

不过它要求有4个函数和3层函数调用来实现上述目标。别忘了:4个函数的要求执行起来并非易事,很容易出错,当1个函数有了变动,其他函数也会受到影响。

举个例子:新函数addItem用于为自动贩卖机(vending machine)添加额外条目,但添加新条目会受到一定限制:

  1. 名称不能为空;
  2. 单词首字母必须大写(如Big Candy Bar);
  3. 价格必须低于100。

我很确定,可以在这儿更新validateItem函数以添加这些新的要求。我们不仅要确认什么情况下调用vent,还要清楚vent对于自动贩卖机中不满足要求的数据是没有用的。

下面的函数可不是摆设哦。这种特定类型的重构决定了我得在真正编码的时候解决这一类问题。

reduceDepositedCoinsBy(price: Int)

假设已调用了validate,这个函数会导致数据损坏。在使用之前,必须确保此操作是合法的,否则就没有意义了。

removeFromInventory(var item: Item, name: String)

这个函数同样要注意数据损坏的问题!

itemNamed(name: String) throws -> Item

这个函数有点儿意思——如果Swift有抛出异常的话,它就没必要存在了。不过,原则上来讲,不是说这个函数不好,而是它太容易出错,是典型的guard语句。

private func itemNamed(name: String) throws -> Item {
    guard let item = inventory[name] {
        throw VendingMachineError.InvalidSelection
    }
    return item
}

这个客观上来说更好一些,能确保guard语句后唯一存在的代码路径是容许字典里有那个条目的;同时还保证,如果字典里没有那个条目的话,能尽早查出来。

总结

千万不能一时兴起,随随便便就进行代码重构,否则很容易将代码复杂化,导致代码中出现错误路径。

我的指导原则是:一个函数应该专注于自己的职责,做好本分就够了,经过多少步骤都只是华而不实的考虑而已。

英文来源:RE: WHY SWIFT GUARD SHOULD BE AVOIDED

作者:David Owens II(@owensd),软件工程师

翻译:张新慧

审校/责任编辑:唐小引

相关推荐

没见过的 Java 编程入门教程!例程使用中文标识符代码:问个好吧
没见过的 Java 编程入门教程!例程使用中文标识符代码:问个好吧

前言Java教程用中文写(如下)更能被新手理解学习。可惜至今没有看到类似入门教程,在此敢为人先。注意:本教程的所有Java代码都可以正确运行,因为Jav...

2023-03-21 18:13 xiyangw

教你简单入门编程(入门编程教程)

首先,别光想,干就好了;然后就下一步下一步了,就o了。什么不信,那先试试吧...

初学Java如何写好代码(java写代码的思路)
初学Java如何写好代码(java写代码的思路)

初学Java的同学时常会遇到这样的情况,跟着入门教程看过一遍,但需要自己写代码的时候却无从下手;写代码的时候时常会遇到不懂的地方,如果停下来去详细了解,可能会花...

2023-03-21 18:12 xiyangw

「好课堂在线」用python和pygame游戏编程入门-控制角色移动

在上一节中我们知道了事件,以及如何捕捉键盘事件进行响应,本届我们结合第一节和上一节的内容,做一个用键盘控制角色移动的功能,代码如下:#用python和pygame游戏编程入门-控制角色移动##...

自学编程怎么入门?很多新人的做法都错了(自学编程怎样入门)
自学编程怎么入门?很多新人的做法都错了(自学编程怎样入门)

自从在网上和大家常常聊聊关于自学编程的话题后遇到很多0基础或者初学编程的朋友,大家给我的感觉是摸不着头脑,很多很简单的问题会走弯路,弄不明白。总结一下,主要以下...

2023-03-21 18:11 xiyangw

单片机入门-Proteus绘制电路和Keil写代码视频教学

视频教程如下:视频加载中...1打开ISIS,点击P2输入AT89C51,选取放入电路图3再点击P,输入led-yellow,res,分别添加LED和电阻,电阻阻值设为100欧,放在电路图,并连线,...

一张图学会编写我的第一行Java代码(如何编写第一个java程序)
一张图学会编写我的第一行Java代码(如何编写第一个java程序)

我的第一行Java代码Eclipse下编写编写我的第一行Java代码你也可以[笑]...

2023-03-21 18:09 xiyangw

入门写程序代码,达到月薪过万,那也是需要时间来开悟

高考结束,每个人都会纠结志愿的填报。本来想填报医学院的志愿,可一考虑到当医生经常会遇到一些血腥的场面,索性还是放弃了。同时也放弃了与那些白衣天使美女们相遇的机会,内心虽有一万个不舍,但也是迫不得已。最...

JAVA小白必学的代码编程技巧(java代码编写教程)

什么是SpringBootJava(面向对象编程语言)经过30多年的发展,产生了非常多的优秀框架。Spring(为解决企业应用程序开发的复杂性而创建的框架)曾是最受欢迎的Java框架之一,但...

没有一行代码的编程入门(一行代码5个bug)
没有一行代码的编程入门(一行代码5个bug)

来看一句话:‘’美丽的穿红衣服的姑娘笑着,和英俊的帅哥一起跳舞‘’美丽,穿红衣服的,英俊的—形容词姑娘帅哥—名词跳舞,笑着—动词写作的时候是一起描述的但是编程...

2023-03-21 18:08 xiyangw

尚学堂分享:编程初学者如何学写代码(编程代码 初学者)
尚学堂分享:编程初学者如何学写代码(编程代码 初学者)

作为编程初学者如何学写代码?这是一个不可回避的话题。相信很多人都一样,那就是先阅读别人写的代码,然后就是读那些你常用的库、编程框架的源代码,读大牛级别的源代码,...

2023-03-21 18:08 xiyangw

STM32编程怎么入门,聊聊我的入门经历(stm32 编程)
STM32编程怎么入门,聊聊我的入门经历(stm32 编程)

我第一次接触STM32大概是在8,9年前。当时刚出来工作不久,在此之前主要用stc和nxp的单片机比较多。那个时候还没有固件库开发的概念,基本都是配置寄存器去使...

2023-03-21 18:08 xiyangw

新手入门小程序尝试写代码?这里有(编程小程序代码)

新手学编程学的没有信心?来这里调节一下重获自信!以下例子都很简单实用,非常适合初学者用来练习。大家也可尝试根据项目的目的及提示,自己构建解决方法,提高编程水平。除此之外,小编还整理了更多适合小白的...

初学者怎样看懂代码?零基础学编程教你快速理解代码
初学者怎样看懂代码?零基础学编程教你快速理解代码

在学习编程的初期,看不懂代码是非常正常的现象,因为程序代码的背后涉及到编程语法、资源整合、算法设计、数据结构等一系列内容,要想搞清楚这些代码的含义,必须为自己制...

2023-03-21 18:07 xiyangw

安卓APP开发 | 简单学Java从编程入门开始-代码中的关键字
安卓APP开发 | 简单学Java从编程入门开始-代码中的关键字

安卓开发需要有语言编程基础,新手开始学习编程的时候一般是从程序语言的最基础内容开始。我现在就以自己熟悉的Java编程语言来讲,一般新手刚入门要首先认识代码中的关...

2023-03-21 18:07 xiyangw

取消回复欢迎 发表评论: