Swift 框架中的正确命名空间(或 class 命名)约定(针对 iOS)
Proper namespacing (or class naming) convention in Swift frameworks (for iOS)
TLDR
如果框架被称为AEConicalGradient,它的class应该被称为ConicalGradientLayer并且ConicalGradientView 或者只是 Layer 和 View?
如果框架被称为AELog,并且它有class也被称为AELog和其他class 调用了 Line 和一些使用此 Line 类型的委托回调,如果您的代码还定义了类型调用,如何实现此委托行,因为在方法签名func didLog(line: AELog.Line)
中添加框架名称作为前缀会产生错误'Line' is not a member type of 'AELog'
,实际上它不是(它是[=85=的一部分]AELog 框架,但它不是 AELog class 的成员。
阅读更多
在为 Swift 3 更新我的几个框架时,我对框架 classes 的正确命名约定有很多重新思考,具体取决于框架名称本身。
最后我意识到我并没有真正跨不同的框架使用相同的约定,所以现在我不喜欢这种缺乏一致性。
我将直接跳到我遇到的一些现实世界的例子:
1.示例:框架没有名为 class 的框架名称:
框架名为 AEConicalGradient,它包含 2 public classes:
- CALayer 子class
- UIView 子class
每个 class 的专有名称应该是什么?
a) AEConicalGradientLayer 和 AEConicalGradientView
b) ConicalGradientLayer 和 ConicalGradientView
c) 图层 和视图
讨论:
a) 我在第一个版本的框架中使用了这个,在单个 AEConicalGradient.swift 文件中使用了这两个 classes。我不再喜欢这种方法,我将源代码分成多个文件,所以现在我在考虑 b) 和 c) 方法.
b) 在这种方法中,我喜欢这样一个事实,即有人可以将这些文件拖到项目中(例如,不使用任何依赖管理器)或 copy/paste 代码,它不会丢失上下文太多了(因为名称清晰),但另一方面,如果您将其视为 AEConicalGradient.ConicalGradientLayer 和 [=237,这听起来有点重复=].
c) AEConicalGradient.Layer 和 AEConicalGradient.View 听起来像我想要的方式,但另一方面,如果有人拥有自己的 Layer 或 View classes,则它们更有可能发生冲突,或者如果他们只是拖动文件或 copy/paste 代码上下文几乎丢失(比如这是什么 Layer 或 View class为了?)。
2。示例:框架确实有一个名为 class 的框架名称:
框架名为 AELog,它由 3 个 public classes 和一个委托协议组成:
- 共享实例(及其委托)
- 日志行模型
- 配置
讨论:
a) 类似于第一版框架中的第一个示例我有 classes 命名为 AELog, AELogDelegate 、AELogLine 和 AELogConfig - 都在单个 AELog.swift 文件中。
b) 在 Swift 3 的最新更新中,我得到了多个文件和 class 名称:AELog,AELogDelegate、行和配置。
那时我才意识到,如果您 import AELog
并实施 AELogDelegate
(它只有 func didLog(line: Line)
)并且您已经有一个不同的 Line
class 在你自己的模块中定义 它会产生冲突,只能通过重命名这两个 Line
classes!
老实说,我不太明白如何避免这种情况。因为如果你尝试在像 func didLog(line: AELog.Line)
这样的委托方法中命名空间类型,你会得到错误 'Line' is not a member type of 'AELog'
而实际上它不是(它是 AELog 框架 的一部分,但它不是 AELog class 的成员。
那时我开始对这个 "loose" 命名有点担心。对这个具体问题有什么建议或意见吗?
c) 本着非常 "loose" 命名的精神,就像 1.c) 方法一样,重命名 AELog class 仅 Log,AELogDelegate 仅 Delegate?此修复错误是否会在 2.b) 中说明,因为没有 class 与框架名称相同,因此编译器可能会识别 AELog.Line 在那种情况下?
问题:
关于这些方法中的任何一种,有哪些 "clean code" 论点?是否有一个明显的 "proper" 方法来说明应该如何完成?我是不是漏掉了什么重要的东西?
你不可能取悦所有人。记住这一点。所以问题可能需要 "what works out best for most"?
(1) "AEConicalGradient.ConicalGradientView" 没有冗余。
(2) 开发人员可以通过多种方式将您的 "Layer" class 导入到他们的项目中。您需要确保他们能够在不增加复杂性的情况下完成工作。我会选择最 "general" 导入方式 - 导入整个框架,而不是单个文件 - 而不是导入 "Layer" 文件。
(3) 我显示了我的年龄,但在 Xcode.
中没有与 "include" 文件相似的内容
从那开始,我想说的是在最深层次上尽可能保持通用 - 创建一个 "layer" 文件和 class,然后让用户进行所需的手动更改它 "AELayer" 如果他们决定导入单个文件。毕竟,他们正在抓取一个文件,对吧?
所以我选择的层次结构是:
AEFramework
Canonical
Layer
View
日志
Delegate
Line
Config
您可以选择各个文件中需要包含的内容。这是我建议的框架设置:
文件"AEFramework.swift"(这也是你的目标):
public class Canonical {
}
文件"Canonical.swift":
extension Canonical {
public class View: UIView {
}
public class Layer: CALayer {
}
}
文件"Layer.swift":
extension Canoncial.Layer {
}
最简单的使用方法是:
import AEFramework
let myLayer = Canoncial.Layer()
最复杂的方法是在将 "Layer.swift" 添加到您的项目后更改它:
extension CALayer {
}
TL;DR
类型名称应为 ConicalGradientView 和 ConicalGradientLayer。 "View" 和 "Layer" 对于 "view" 或 "layer" 概念的描述不够充分。
Swift 编译器无法在该上下文中消除冲突模块/类型名称的歧义。您不会找到来自 Apple 或第三方的代码,这些代码使用框架/模块与其中类型的冲突名称。这可能是出于技术原因,但它也会令人困惑,并且您将 'AELog' 作为 Swift 类型名称的情况也不符合惯用语。
长答案
类型的名称在您使用该类型的程序中应该以某种方式 describe its role。虽然这当然是主观的,但我认为 "View" 不是一个非常具有描述性的名称view subclass,假设仅 Cocoa 中就有数十个 NSView / UIView subclasses,并且视图在您自己的应用程序中可能扮演数百个角色。因此,根据逻辑,仅通过单独查看非限定类型名称,您无法真正猜测它的作用,因此它不是一个好名字。模块/命名空间名称的功能更多是提供最小级别的歧义消除,这会导致名称冲突的未定义行为(例如,传统上在 C / Objective-C 中不可用的奢侈),但可以说它的作用不是常规的以完全限定形式使用。
也从 "what if I wanted to introduce a new variant of a View in my framework?" 的角度考虑一下 – 例如,专门针对 圆锥形 渐变的单独框架听起来有点滑稽。对于具有渐变的不同类型的视图,一个框架可能听起来更合理 "minimal size" (即使您可能只为您的 conical 实施了案例现在需要),这同样适用于像 "Layer" 这样的概念。例如,如果 "AEGradientView" 是您的框架的名称,那么您可以在其中包含 ConicalGradientView、RadialGradientView 等内容,并且可以很好地读出。最后,如果您希望在使用该框架的 API 时使事情变得更简洁,您始终可以使用 typealias
。
因此,充分描述是一个因素,但简洁当然是您要平衡的另一个因素。如果您真的确实有一个类型的案例在框架中确实是独一无二的,并且类型名称既可以简短又可以清楚地表明其作用,那么至少我的惯例确实是使用尽可能简短的名称。因此,例如在我共同设计的某个图像数据和元数据处理框架中,Image
是用作图像数据和元数据容器的类型的名称。因为在该框架的行话中确实只有一个 class 在 "image" 角色中,而且至关重要的是,它清楚地描述了 class 的用途(不同于 "View").同样,我对嵌套类型使用尽可能简短的名称,例如,用于表示 "image error"(符合 Swift.Error
的枚举)的类型称为 Carpaccio.Image.Error
.
关于您关于模块/类型名称冲突的第二个问题,编译器无法在该上下文中解决这种歧义。您确实也不会在任何 Apple 框架中发现模块和类型名称混淆的任何实例(我也想不到在第 3 方代码中遇到过任何此类示例)。除了编译器很可能无法在模块和那里的冲突 class 名称之间消除歧义的技术原因之外,对于遵循平台约定的程序员来说,它也会造成混淆:将模块名称视为 "product" 和里面的类型作为组成部分——虽然 AELog
是 Swift 中日志框架的好名字,但它不是 Swift 代码中类型的惯用名称; "AE" 之类的名称前缀只是没有在 Swift 中用于类型——它们甚至对于您在 Swift 中创建的 Objective-C subclasses 也不是必需的,因为Objective-C 运行时看到的 class 的完全限定名称实际上包括模块名称作为前缀。
今年早些时候在 Swift API naming considerations 上也有一个很好的 WWDC 谈话,也讨论了上面提到的一些内容。
TLDR
如果框架被称为AEConicalGradient,它的class应该被称为ConicalGradientLayer并且ConicalGradientView 或者只是 Layer 和 View?
如果框架被称为AELog,并且它有class也被称为AELog和其他class 调用了 Line 和一些使用此 Line 类型的委托回调,如果您的代码还定义了类型调用,如何实现此委托行,因为在方法签名
func didLog(line: AELog.Line)
中添加框架名称作为前缀会产生错误'Line' is not a member type of 'AELog'
,实际上它不是(它是[=85=的一部分]AELog 框架,但它不是 AELog class 的成员。
阅读更多
在为 Swift 3 更新我的几个框架时,我对框架 classes 的正确命名约定有很多重新思考,具体取决于框架名称本身。
最后我意识到我并没有真正跨不同的框架使用相同的约定,所以现在我不喜欢这种缺乏一致性。
我将直接跳到我遇到的一些现实世界的例子:
1.示例:框架没有名为 class 的框架名称:
框架名为 AEConicalGradient,它包含 2 public classes:
- CALayer 子class
- UIView 子class
每个 class 的专有名称应该是什么?
a) AEConicalGradientLayer 和 AEConicalGradientView
b) ConicalGradientLayer 和 ConicalGradientView
c) 图层 和视图
讨论:
a) 我在第一个版本的框架中使用了这个,在单个 AEConicalGradient.swift 文件中使用了这两个 classes。我不再喜欢这种方法,我将源代码分成多个文件,所以现在我在考虑 b) 和 c) 方法.
b) 在这种方法中,我喜欢这样一个事实,即有人可以将这些文件拖到项目中(例如,不使用任何依赖管理器)或 copy/paste 代码,它不会丢失上下文太多了(因为名称清晰),但另一方面,如果您将其视为 AEConicalGradient.ConicalGradientLayer 和 [=237,这听起来有点重复=].
c) AEConicalGradient.Layer 和 AEConicalGradient.View 听起来像我想要的方式,但另一方面,如果有人拥有自己的 Layer 或 View classes,则它们更有可能发生冲突,或者如果他们只是拖动文件或 copy/paste 代码上下文几乎丢失(比如这是什么 Layer 或 View class为了?)。
2。示例:框架确实有一个名为 class 的框架名称:
框架名为 AELog,它由 3 个 public classes 和一个委托协议组成:
- 共享实例(及其委托)
- 日志行模型
- 配置
讨论:
a) 类似于第一版框架中的第一个示例我有 classes 命名为 AELog, AELogDelegate 、AELogLine 和 AELogConfig - 都在单个 AELog.swift 文件中。
b) 在 Swift 3 的最新更新中,我得到了多个文件和 class 名称:AELog,AELogDelegate、行和配置。
那时我才意识到,如果您 import AELog
并实施 AELogDelegate
(它只有 func didLog(line: Line)
)并且您已经有一个不同的 Line
class 在你自己的模块中定义 它会产生冲突,只能通过重命名这两个 Line
classes!
老实说,我不太明白如何避免这种情况。因为如果你尝试在像 func didLog(line: AELog.Line)
这样的委托方法中命名空间类型,你会得到错误 'Line' is not a member type of 'AELog'
而实际上它不是(它是 AELog 框架 的一部分,但它不是 AELog class 的成员。
那时我开始对这个 "loose" 命名有点担心。对这个具体问题有什么建议或意见吗?
c) 本着非常 "loose" 命名的精神,就像 1.c) 方法一样,重命名 AELog class 仅 Log,AELogDelegate 仅 Delegate?此修复错误是否会在 2.b) 中说明,因为没有 class 与框架名称相同,因此编译器可能会识别 AELog.Line 在那种情况下?
问题:
关于这些方法中的任何一种,有哪些 "clean code" 论点?是否有一个明显的 "proper" 方法来说明应该如何完成?我是不是漏掉了什么重要的东西?
你不可能取悦所有人。记住这一点。所以问题可能需要 "what works out best for most"?
(1) "AEConicalGradient.ConicalGradientView" 没有冗余。
(2) 开发人员可以通过多种方式将您的 "Layer" class 导入到他们的项目中。您需要确保他们能够在不增加复杂性的情况下完成工作。我会选择最 "general" 导入方式 - 导入整个框架,而不是单个文件 - 而不是导入 "Layer" 文件。
(3) 我显示了我的年龄,但在 Xcode.
中没有与 "include" 文件相似的内容从那开始,我想说的是在最深层次上尽可能保持通用 - 创建一个 "layer" 文件和 class,然后让用户进行所需的手动更改它 "AELayer" 如果他们决定导入单个文件。毕竟,他们正在抓取一个文件,对吧?
所以我选择的层次结构是:
AEFramework
Canonical
Layer
View
日志
Delegate
Line
Config
您可以选择各个文件中需要包含的内容。这是我建议的框架设置:
文件"AEFramework.swift"(这也是你的目标):
public class Canonical {
}
文件"Canonical.swift":
extension Canonical {
public class View: UIView {
}
public class Layer: CALayer {
}
}
文件"Layer.swift":
extension Canoncial.Layer {
}
最简单的使用方法是:
import AEFramework
let myLayer = Canoncial.Layer()
最复杂的方法是在将 "Layer.swift" 添加到您的项目后更改它:
extension CALayer {
}
TL;DR
类型名称应为 ConicalGradientView 和 ConicalGradientLayer。 "View" 和 "Layer" 对于 "view" 或 "layer" 概念的描述不够充分。
Swift 编译器无法在该上下文中消除冲突模块/类型名称的歧义。您不会找到来自 Apple 或第三方的代码,这些代码使用框架/模块与其中类型的冲突名称。这可能是出于技术原因,但它也会令人困惑,并且您将 'AELog' 作为 Swift 类型名称的情况也不符合惯用语。
长答案
类型的名称在您使用该类型的程序中应该以某种方式 describe its role。虽然这当然是主观的,但我认为 "View" 不是一个非常具有描述性的名称view subclass,假设仅 Cocoa 中就有数十个 NSView / UIView subclasses,并且视图在您自己的应用程序中可能扮演数百个角色。因此,根据逻辑,仅通过单独查看非限定类型名称,您无法真正猜测它的作用,因此它不是一个好名字。模块/命名空间名称的功能更多是提供最小级别的歧义消除,这会导致名称冲突的未定义行为(例如,传统上在 C / Objective-C 中不可用的奢侈),但可以说它的作用不是常规的以完全限定形式使用。
也从 "what if I wanted to introduce a new variant of a View in my framework?" 的角度考虑一下 – 例如,专门针对 圆锥形 渐变的单独框架听起来有点滑稽。对于具有渐变的不同类型的视图,一个框架可能听起来更合理 "minimal size" (即使您可能只为您的 conical 实施了案例现在需要),这同样适用于像 "Layer" 这样的概念。例如,如果 "AEGradientView" 是您的框架的名称,那么您可以在其中包含 ConicalGradientView、RadialGradientView 等内容,并且可以很好地读出。最后,如果您希望在使用该框架的 API 时使事情变得更简洁,您始终可以使用 typealias
。
因此,充分描述是一个因素,但简洁当然是您要平衡的另一个因素。如果您真的确实有一个类型的案例在框架中确实是独一无二的,并且类型名称既可以简短又可以清楚地表明其作用,那么至少我的惯例确实是使用尽可能简短的名称。因此,例如在我共同设计的某个图像数据和元数据处理框架中,Image
是用作图像数据和元数据容器的类型的名称。因为在该框架的行话中确实只有一个 class 在 "image" 角色中,而且至关重要的是,它清楚地描述了 class 的用途(不同于 "View").同样,我对嵌套类型使用尽可能简短的名称,例如,用于表示 "image error"(符合 Swift.Error
的枚举)的类型称为 Carpaccio.Image.Error
.
关于您关于模块/类型名称冲突的第二个问题,编译器无法在该上下文中解决这种歧义。您确实也不会在任何 Apple 框架中发现模块和类型名称混淆的任何实例(我也想不到在第 3 方代码中遇到过任何此类示例)。除了编译器很可能无法在模块和那里的冲突 class 名称之间消除歧义的技术原因之外,对于遵循平台约定的程序员来说,它也会造成混淆:将模块名称视为 "product" 和里面的类型作为组成部分——虽然 AELog
是 Swift 中日志框架的好名字,但它不是 Swift 代码中类型的惯用名称; "AE" 之类的名称前缀只是没有在 Swift 中用于类型——它们甚至对于您在 Swift 中创建的 Objective-C subclasses 也不是必需的,因为Objective-C 运行时看到的 class 的完全限定名称实际上包括模块名称作为前缀。
今年早些时候在 Swift API naming considerations 上也有一个很好的 WWDC 谈话,也讨论了上面提到的一些内容。