如果名称中包含空格会怎样?






4.33/5 (3投票s)
常量、变量、方法、类和命名空间的名称中不允许使用空格是否存在技术原因,还是符合某种约定?
引言
常量、变量、方法、类和命名空间的名称中不允许使用空格是否存在技术原因,还是符合某种约定?这个问题也可以问及不能放在名称开头的数字。
遵循命名约定的主要原因是减少阅读和理解源代码所需的精力。开发者可以专注于比争论语法和命名标准更重要的问题。因此,有一个严格的规则,即名称通常区分大小写。名称可以是任何合法的标识符——一个无限长度的 Unicode 字母和数字序列,以字母或下划线字符开头。名称中不允许有空格。
最后一条规则不仅用于解决代码理解方面的困难。编译器需要找出单词的含义。它使用“状态机”方法,需要区分关键词。但是,像 SQL 或 Maple 这样的语言允许名称包含空格。它们用特殊的引号字符括在两边:SQL 中的“[”和“]”,Maple 中的“`”(U+0060,重音符)。在 C# 中,方括号用作集合项目的索引器。但是重音符可以成功地用作封闭符号。
代码示例
让我们尝试用 C# 编写代码,使用包含空格的相当长的名称,看看会发生什么。
[`Custom Serialization Attribute`]
public class `Config Data File Repository` : `Configuration Repository Interface` {
public enum `Data Visualization Format` { `2D`, `3D` }
public `Data Visualization Format` `Visualization Format` { get; set; }
= `Data Visualization Format`.`2D`;
...
private readonly string `repository file name`;
public `Config Data File Repository`(string `repository file name`) {
this.`repository file name` = `repository file name`;
}
public `Configuration Data` Load() {
using(var fs = new `File Stream`(`repository file name`, `File Mode`.Open)) {
return `Load From Stream`(fs);
}
}
public void Save(`Configuration Data` `current configuration`) {
using (var fs = new `File Stream`(
this.`repository file name`, `File Mode`.`Create New`)) {
`Save To Stream`(`current configuration`, fs);
}
}
...
public const string `DEFAULT REPOSITORY FILE` =
"Default Config Data File Repository.config";
public static `Config Data File Repository` `Create Config Data File Repository`(
string `file Name` = `Config Data File Repository`.`DEFAULT REPOSITORY FILE`) {
return new `Config Data File Repository`(`file Name`);
}
}
此外,让我们用 Java 编写代码,这与现实世界的问题非常接近。
@Entity
@Table(name = "[PERSONAL CONFIGURATION SECTIONS]")
@EntityListeners( { HierarchyListener.class } )
@NamedQueries({
@NamedQuery(
name = "`Personal Configuration Section`.`find All`",
query = "SELECT cs FROM [PERSONAL CONFIGURATION SECTIONS] cs"),
@NamedQuery(
name = "`Personal Configuration Section`.`find By Configuration Section Id`",
query = "SELECT cs FROM [CONFIGURATION SECTIONS] cs "
+ "WHERE cs.[configuration Section Id] = :`configuration Section Id`")})
public class `Personal Configuration Section`
implements Serializable, `Hierarchy Element Interface` {
private static final long `serial Version UID` = 1L;
@Id @NotNull
@Basic(optional = false)
@`Generated Value`(
strategy = `Generation Type`.SEQUENCE,
generator = "global_id_gen")
@`Sequence Generator`(name = "global_id_gen", `sequence Name` = "GLOBAL_ID_GEN")
@Column(name = "[CONFIGURATION SECTION ID]")
private Integer `configuration Section Id`;
public Integer `get Configuration Section Id`()
{ return `configuration Section Id`; }
public void `set Configuration Section Id`(Integer `configuration Section Id`)
{ this.`configuration Section Id` = `configuration Section Id`; }
@Column(name = "[FULL NAME]")
private String `full Name`;
public String `get Full Name`()
{ return `full Name`; }
public void `set Full Name`(String `full Name`)
{ this.`full Name` = `full Name`; }
@Column(name = "[EXPERIENCE, SKILLS AND ARTIFACTS]")
private `Collection Interface` `experience, skills and artifacts`;
public `Collection Interface` `get Experience, skills and artifacts`()
{ return `experience, skills and artifacts`; }
public void `set Experience, skills and artifacts`(
`Collection Interface` `experience, skills and artifacts`)
{ this.`experience, skills and artifacts` = `experience, skills and artifacts`; }
@`Many To One`(fetch = `Fetch Type`.LAZY)
@`Join Columns`({
@`Join Column`(
name="[PARENT ID]",
`referenced Column Name`="parent Configuration Section Id"),
@`Join Column`(
name="[PARENT VERSION]",
`referenced Column Name`="parent Configuration Section Version")
})
private `Personal Configuration Section` parent;
public `Personal Configuration Section` `get Parent`()
{ return parent; }
public void `set Parent`(`Personal Configuration Section` parent)
{ this.parent = parent; }
@`One To Many`(fetch=`Fetch Type`.LAZY, `mapped By`="parent")
private Set<`Personal Configuration Section`> children;
public Set<`Personal Configuration Section`> `get Children`() { return children; }
public `Personal Configuration Section`() {}
public `Personal Configuration Section`(
Integer `personal Configuration Section Id`) {
this.`personal Configuration Section Id` = `personal Configuration Section Id`;}
...
}
毫无疑问,可以使编译器解析此代码。但是,代码变得更难以阅读。令我惊讶的是,代码的可读性只是略有下降,尤其是对于 Java 而言!首先是已经存在的名称过长的问题。有大量文章(“编程搭档认为提供良好描述的非常长的描述性名称”或“变量和方法命名的最佳实践”)提供了一些有用的解决方案。这个问题自面向对象语言诞生以来就一直存在。根据我的观点,在思考代码时,从可能使用它的其他开发人员的角度来看它是有用的。这将不仅有助于选择名称,而且有助于使您的代码更具可读性,而无需编写文档和不必要的注释。如果名称太长,那么这部分代码可能具有多个职责,应该单独编写。换句话说,代码应该被重构。
此外,还有一个问题,即如何提高可读性以及在哪里使用该功能。主要的应用程序领域可以定义为单元测试类和包含由 string
资源或配置设置部分包装类实现的国际化 string
属性的类。由于 IDE 的功能,可读性可以得到提高。例如,带有空格的名称可以用细虚线边框突出显示。这种方法将允许开发人员直观、快速地识别此类名称,并将限制对带有空格的名称的广泛、草率的使用。
让我们尝试用 C# 编写一个简单的单元测试。
此外,上面给出的单元测试用 Java 重新编写。
C# 和 Java 中的单元测试代码具有非常好的可读性。它不需要其他属性就能在测试报告窗口中正确显示。但是,指定测试类别的属性可能会很有用。
在代码中经常使用这种长名称不是最好的方法。但是,如果需要引用它们,则可以使用自然语言中提出的方法来减少此类名称。名称中的一些不重要部分可以用省略号字符代替。
结论
我非常感谢读者表达他们的观点并回答以下问题。重新考虑名称带空格的情况是否已经到来?并且在哪些领域编写此类名称非常重要?也许是时候重新思考命名约定了。
关注点
很高兴找到并学习好的软件工程原则,源代码中的好方法和现代框架使我们能够编写真正灵活的代码。
历史
- 2016 年 4 月 1 日 - 第一个版本