是否值得学习该约定,或者它是否会损害可读性和可维护性?
20 回答
考虑到大多数使用匈牙利符号的人都在遵循被误解的版本,我会说这毫无意义。
如果你想使用它的原始定义,它可能更有意义,但除此之外它主要是语法糖。
如果您阅读有关该主题的Wikipedia 文章,您会发现两个相互冲突的表示法,Systems Hungarian Notation和Apps Hungarian Notation。
原始的,好的,定义是Apps Hungarian Notation,但大多数人使用Systems Hungarian Notation。
作为这两者的一个例子,考虑用 l 表示长度、a 表示面积和 v 表示体积作为变量的前缀。
使用这种表示法,以下表达式是有意义的:
int vBox = aBottom * lVerticalSide;
但这不是:
int aBottom = lSide1;
如果您混合前缀,它们将被视为等式的一部分,并且体积 = 面积 * 长度对于盒子来说很好,但是将长度值复制到面积变量中应该会引发一些危险信号。
不幸的是,另一种表示法不太有用,人们在变量名称前加上值的类型,如下所示:
int iLength;
int iVolume;
int iArea;
有些人使用 n 表示数字,或 i 表示整数,f 表示浮点数,s 表示字符串等。
最初的前缀是用来发现方程中的问题,但不知何故已经演变成使代码更容易阅读,因为你不必去寻找变量声明。对于今天的智能编辑器,您只需将鼠标悬停在任何变量上即可找到完整类型,而不仅仅是它的缩写,这种类型的匈牙利符号已经失去了很多意义。
但是,你应该自己决定。我只能说我也不用。
编辑只是为了添加一个简短的通知,虽然我不使用Hungarian Notation,但我确实使用了前缀,它是下划线。我在类的所有私有字段前面加上一个 _ ,否则拼写它们的名称,就像我拼写一个属性一样,首字母大写。
如果使用得当,匈牙利命名约定会很有用,但不幸的是,它往往被误用的频率更高。
阅读 Joel Spolsky 的文章Making Wrong Code Look Wrong以获得适当的观点和理由。
本质上,基于类型的匈牙利表示法,其中变量以有关其类型的信息为前缀(例如,对象是否为字符串、句柄、int 等)大多是无用的,并且通常只会增加开销而几乎没有好处。遗憾的是,这是大多数人都熟悉的匈牙利符号。然而,所设想的匈牙利符号的意图是添加关于变量包含的数据“种类”的信息。这允许您将不应该被允许混合在一起的其他类型的数据划分类型的数据,除非可能通过一些转换过程。例如,基于像素的坐标与其他单位的坐标,或不安全的用户输入与来自安全来源的数据等。
以这种方式看待它,如果您发现自己通过代码来查找有关变量的信息,那么您可能需要调整命名方案以包含该信息,这就是匈牙利约定的精髓。
请注意,匈牙利表示法的替代方法是使用更多类来显示变量使用的意图,而不是到处依赖原始类型。例如,您可以为不安全的用户输入使用简单的字符串包装器类,并为安全数据使用单独的包装器类,而不是为不安全的用户输入使用变量前缀。在强类型语言中,这具有由编译器强制执行分区的优势(即使在不太强类型的语言中,您通常也可以添加自己的tripwire代码),但会增加不少开销。
当涉及到 UI 元素时,我仍然使用匈牙利表示法,其中几个 UI 元素与特定的对象/值相关,例如,
lblFirstName 为标签对象,txtFirstName 为文本框。我绝对不能将它们都命名为“FirstName”,即使这是两个对象的关注/责任。
其他人如何命名 UI 元素?
我认为匈牙利符号是通往更易读代码的“路径”的一个有趣的脚注,如果做得好,比不做更好。
尽管如此,我宁愿取消它,而不是这样:
int vBox = aBottom * lVerticalSide;
写这个:
int boxVolume = bottomArea * verticalHeight;
现在是 2008 年。我们不再有 80 个字符的固定宽度屏幕了!
此外,如果您编写的变量名比那个长得多,那么无论如何您都应该考虑重构为对象或函数。
它毫无意义(而且会分散注意力),但在我的公司中使用率相对较高,至少对于整数、字符串、布尔值和双精度数等类型而言。
sValue
, iCount
,dAmount
或fAmount
,之类的东西bFlag
无处不在。
曾几何时,这种约定是有充分理由的。现在,它是一种癌症。
很抱歉跟进一个问题,但是带有“I”前缀的接口是否符合匈牙利表示法?如果是这样的话,那么是的,很多人在现实世界中使用它。如果没有,请忽略这一点。
当我看到匈牙利语的讨论时,我很高兴看到人们在努力思考如何让他们的代码更清晰,以及如何让错误更明显。这正是我们都应该做的!
但是不要忘记,除了命名之外,您还可以使用一些强大的工具。
提取方法如果您的方法太长以至于您的变量声明已经滚动到屏幕顶部,请考虑使您的方法更小。(如果你有太多的方法,考虑一个新的类。)
强类型化如果你发现你将zip code存储在一个整数变量中并将它们分配给一个shoe size整数变量,考虑为 zip code 创建一个类和一个鞋码类。然后您的错误将在编译时被捕获,而不需要人工仔细检查。当我这样做时,我通常会在我的代码中找到一堆特定于邮政编码和鞋码的逻辑,然后我可以将它们转移到我的新课程中。突然间,我的所有代码都变得更清晰、更简单,并且不受某些类型的错误的影响。哇。
总结一下:是的,请认真思考如何在代码中使用名称来清楚地表达您的想法,但也要看看您可以调用的其他强大的 OO 工具。
这些天范围不是比类型更重要吗,例如
- l 本地
- 一个 for 论点
- m代表会员
- g 代表全局
- ETC
使用重构旧代码的现代技术,搜索和替换符号因为你改变了它的类型是乏味的,编译器会捕捉到类型变化,但通常不会捕捉到范围的不正确使用,明智的命名约定在这里有所帮助。
我不使用非常严格意义上的匈牙利符号,但我发现自己使用它来保留一些常见的自定义对象以帮助识别它们,而且我倾向于在 gui 控件对象前面加上它们是控件的类型。例如,labelFirstName、textFirstName 和 buttonSubmit。
我对按钮、文本框和标签等 UI 元素使用匈牙利命名法。主要好处是在 Visual Studio Intellisense 弹出窗口中进行分组。如果我想访问我的标签,我只需开始输入 lbl.... 并且 Visual Studio 会建议我所有的标签,nicley 组合在一起。
然而,在做了越来越多 Silverlight 和 WPF 的东西,利用数据绑定之后,我什至不再命名我所有的控件,因为我不必从代码隐藏中引用它们(因为真的没有任何代码隐藏了;)
问题是混合标准。
正确的是确保每个人都做同样的事情。
int Box = iBottom * nVerticleSide
最初的前缀是用来发现方程中的问题,但不知何故已经演变成使代码更容易阅读,因为你不必去寻找变量声明。对于今天的智能编辑器,您只需将鼠标悬停在任何变量上即可找到完整类型,而不仅仅是它的缩写,这种类型的匈牙利符号已经失去了很多意义。
我稍微改掉了这个习惯,但是在没有强变量类型的 JavaScript 中,以类型为前缀可能很有用。
在使用动态类型语言时,我偶尔会使用 Apps Hungarian。对于静态类型的语言,我没有。请参阅我在另一个线程中的解释。
匈牙利符号在类型安全语言中毫无意义。例如,您将在旧 Microsoft 代码中看到的一个常见前缀是“lpsz”,意思是“指向零终止字符串的长指针”。自 1700 年代早期以来,我们还没有使用存在短指针和长指针的分段架构,C++ 中的正常字符串表示总是以零结尾,并且编译器是类型安全的,因此不会让我们将非字符串操作应用于细绳。因此,这些信息对程序员都没有任何实际用途——它只是更多的打字。
但是,我使用了类似的想法:阐明变量用法的前缀。主要有:
- m = 成员
- c = 常量
- s = 静态
- v = 易失性
- p = 指针(和 pp=指向指针的指针等)
- i = 索引或迭代器
这些可以组合,因此作为指针的静态成员变量将是“mspName”。
这些在哪里有用?
- 在用法很重要的地方,不断提醒程序员变量是(例如)易失性或指针是个好主意
- 在我使用 p 前缀之前,指针取消引用曾经让我头疼。现在很容易知道什么时候有一个对象 (Orange) 一个指向对象的指针 (pOrange) 或一个指向对象指针的指针 (ppOrange)。要取消引用一个对象,只需在其名称中的每个 p 前面加上一个星号。案例已解决,不再有 deref 错误!
- 在构造函数中,我通常会发现参数名称与成员变量的名称(例如大小)相同。我更喜欢使用“mSize = size;” 比“size = theSize”或“this.size = size”。它也更安全:当我想说“mSize = 1”(设置成员)时,我不会意外使用“size = 1”(设置参数)
- 在循环中,我的迭代器变量都是有意义的名称。大多数程序员使用“i”或“index”,然后在需要内部循环时必须编造新的无意义名称(“j”、“index2”)。我使用带有 i 前缀的有意义的名称(iHospital、iWard、iPatient),因此我始终知道迭代器正在迭代什么。
- 在循环中,您可以通过使用具有不同前缀的相同基本名称来混合多个相关变量: Orange orange = pOrange[iOrange]; 这也意味着您不会犯数组索引错误(pApple[i] 看起来不错,但将其写为 pApple[iOrange] 并且错误立即显而易见)。
- 许多程序员会在不知情的情况下使用我的系统:通过添加像“Index”或“Ptr”这样的冗长后缀 - 没有任何理由使用比单个字符更长的形式恕我直言,所以我使用“i”和“ p”。更少的打字,更一致,更容易阅读。
这是一个简单的系统,它为代码添加了有意义和有用的信息,并消除了许多简单但常见的编程错误的可能性。
过去 6 个月我一直在 IBM 工作,但我在任何地方都没有看到它(感谢上帝,因为我讨厌它。)我看到了 camelCase 或 c_style。
thisMethodIsPrettyCool()
this_method_is_pretty_cool()
这取决于您的语言和环境。通常我不会使用它,除非您所在的开发环境很难找到变量的类型。
还有两种不同类型的匈牙利符号。参见乔尔的文章。我找不到它(他的名字并不完全让他们很容易找到),有人有我的意思的链接吗?
编辑:Wedge 在他的帖子中有我的意思的文章。
原始形式(正确的匈牙利表示法:)),其中前缀表示变量存储的值的类型(即长度、数量)是可以的,但并非在所有类型的应用程序中都是必需的。
在大多数现代编程语言中,前缀表示类型(String,int)的流行形式(The Wrong Hungarian Notation)是无用的。
尤其是像 strA 这样无意义的名字。我无法理解我们人们使用带有长前缀的无意义名称,这什么都没有。
我对组件(例如editFirstName、lblStatus 等)使用基于类型的(系统HN),因为它使自动完成工作更好。
我有时将 App HN 用于类型信息不足的变量。即 fpX 表示一个固定的指向变量(int 类型,但不能与 int 混合匹配),rawInput 表示尚未验证的用户字符串等
作为一个 PHP 程序员,它的类型非常松散,我不打算使用它。但是,我偶尔会根据系统的大小和变量的范围将某些东西识别为数组或对象。