我对软件开发比较陌生,我正在努力完成我的第一个iPhone应用程序。
在学习Swift的过程中,我了解到我可以在类定义之外添加函数,并且可以在所有视图中访问它。过了一会儿,我发现自己创建了很多全局函数来设置应用程序首选项(注册默认值,UIAppearance等)。
这是不好的做法吗?我能想到的唯一替代方法是创建一个自定义类来封装它们,但是这个类本身不会用于任何目的,我必须想办法将它传递给视图。
答案 0 :(得分:6)
全球职能:好(无论如何,恕我直言,虽然有些人不同意)
全球状态:糟糕(相当普遍认同)
我的意思是,分解代码以创建大量小实用程序函数,使它们成为通用代码并重用它们可能是一种很好的做法。只要它们是“pure functions”
例如,假设您发现自己正在检查数组中的所有条目是否都具有某个属性。您可以在数组上编写for循环来检查它们。您甚至可以重复使用标准reduce
来执行此操作。或者你可以编写一个可重用的函数all
,它接受一个检查元素的闭包,并对数组中的每个元素运行它。当您阅读let allAboveGround = all(sprites) { $0.position.y > 0 }
而不是执行相同操作的for…in
循环的代码时,它很清楚。您还可以专门为您的all
函数编写单独的单元测试,并确信它可以正常工作,而不是对包含其中嵌入all
版本的函数的更多参与测试商业逻辑。
将代码分解为更小的函数也有助于避免需要使用var
这么多。例如,在上面的示例中,您可能需要var
来跟踪循环结果,但可以使用all
分配let
函数的结果。支持用let
声明的不可变变量有助于使程序更容易推理和调试。
正如@drewag在他的回答中所指出的那样,你不应该做的是编写改变全局变量的函数(或访问相同的东西的单例)。您编写的任何全局函数都应仅对其输入进行操作,并且每次都会生成完全相同的结果,无论它们何时被调用。改变全局状态的全局函数(即对全局变量进行更改(或者通过引用更改传递给它们的变量的值)可能会因为它们可能导致的意外副作用而令人难以置信地进行调试。
编写纯全局函数有一个缺点,*就是你最终“污染命名空间” - 也就是说,你有所有这些函数可能与程序的特定部分有特定的关联,但是无处不在。说实话,对于中型应用程序,具有良好编写的通用功能,这可能不是问题。如果函数纯粹用于特定的结构或类,可能使它成为静态方法。如果你的项目真的太大了,你可能会把你最常用的功能分解成一个单独的框架,虽然这是一个非常大的开销/学习练习(并且Swift框架还没有完全成熟),所以如果你刚刚开始,所以我建议现在离开这个,直到你变得更加自信。
*编辑:确定两个缺点 - 成员函数更容易被发现(当你点击时通过自动完成。)
答案 1 :(得分:1)
与@AirspeedVelocity讨论后更新
全局函数可以正常运行,它们与在实际上不包含状态的自定义类型上使用类型方法甚至实例方法完全不同。
整个事情主要归结为个人偏好。以下是一些优点和缺点。
<强>缺点:强>
它们有时会导致意想不到的副作用。也就是说,他们可以改变您或调用者忘记导致难以追踪错误的全局状态。只要您小心不使用全局变量并确保您的函数始终使用相同的输入返回相同的结果而不管系统其余部分的状态,您通常可以忽略此con。
一旦你开始unit testing(在大多数情况下这是一个明确的好政策),他们使用它们的代码难以测试哪个是重要的。很难测试,因为你不能轻易地模拟全局函数的实现。例如,要更改全局设置的值。相反,您的测试将开始依赖于设置此全局设置的其他类。能够将一个设置注入你的班级而不必伪造一个全局函数通常是可取的。
他们有时暗示代码组织不善。您的所有代码都应为separable into small, single purpose, logical units。这可确保您的代码在代码库的大小和年龄增长时仍然可以理解。例外是真正的通用功能,具有非常高级别和可重用的概念。例如,一个允许您测试序列中所有元素的函数。您还可以通过将全局函数分成命名良好的文件,将全局函数分离为逻辑单元。
<强>优点:强>
高级全局函数非常容易测试。但是,您不能忽略仍需要在使用它们的地方测试它们的逻辑,因为您的单元测试不应该在知道您的代码实际实现方式的情况下编写。
轻松访问。将许多类型注入另一个类(将对象传递给初始化器并可能将其存储为属性)通常会很麻烦。全局功能通常可以删除此锅炉板代码(即使它具有较低的灵活性和较低的可测试性)。
最后,每次代码架构决策都是每次使用时权衡的平衡。
答案 2 :(得分:1)
我有一个Framework.swift,它包含一组常见的全局函数,如local(str:String)
,以摆脱NSLocalize
中的第二个参数。此外,还有许多alert
函数在内部使用local
并且具有不同数量的参数,这些参数使用NSAlert
作为模态对话框更加容易。
因此,为此目的,全球职能是好的。在信息隐藏方面,它们是一种坏习惯,你可以将内部类知识暴露给某些全局功能。