程序员都认识匈牙利命名法。
程序员被教导说匈牙利命名法过时了。它的起源地微软都明确表示不建议使用匈牙利命名法。
因为这种命名方法是多余的,只会把事情搞复杂,而没有什么好处。常见的例子是这样的:
for(ni = 0 ; ni <10 ;ni++) {}
这里面有个变量i,根据匈牙利命名法,需要在前面加一个前缀n,表示这个变量是整型。如果它是长整型,那么变量名可能是li。
它的问题在这里,首先这增加了程度员的敲键次数,程序员们不喜欢,程序猿也不会喜欢。其次,付出了多敲键的代价之后,程员发现自己并没有获得什么好处。把i变 成ni有什么意义呢?脱了马甲我就不认得你是个整型了怎地?就算我不认得了,IDE也认得侬啊。
所以这种做法被作为一种蛇足在岁月中不断遭受程序员们的白眼,之后被“不推荐”了。
然而,这是一枚冤案,匈牙利命名法比杨乃武还冤哪,你们程序员纯粹是拉不出便便来还怪地球没有吸引力。本身它就不是这么用的。
原始的匈牙利命名法,现在被称为匈牙利应用命名法,由1972年至1981年在施乐帕洛阿尔托研究中心工作的程序员查尔斯·西蒙尼发明。此人后来成了微软的总设计师。这种命名法其实是对于西蒙尼祖籍的一种讽刺。匈牙利人名和大多数其他欧洲人名相比是反过来的,即姓氏在名字的前面。举个例子,英语化的名字"CharlesSimonyi"在匈牙利语中原本是"SimonyiKároly"。同样的,在匈牙利命名法中,类型名在实际变量名前,而不是像大多数欧洲的Smalltalk那样,类型放在变量名后,例如aPoint和lastPoint。后者在西蒙尼任职于施乐帕洛阿尔托研究中心时期非常流行。这种命名法可能也是受到了一种叫做波兰式的不相关的概念的启发。
匈牙利命名法这个叫法被许多人记住是因为难发音的辅音字串有点像一些东欧语言中辅音丰富的拼写方式,尽管实际上匈牙利语是属于芬兰-乌戈尔语族,而不像斯拉夫语族那样元音丰富。举例来说,零结束字符串的前缀"sz"实际上就是匈牙利字母表中的一个合体字母(参看德语中的ß)
如上所述,原始的匈牙利命名法现在被称匈牙利应用命名法。而一般咸认的匈牙利命名法,就是上文举过例子的,臭名昭著的,其实是匈牙利系统命名法。它是后起的,派生出来的,却盖过了原始方法的光芒,引来臭名后,却盖在匈牙利命名法身上。有点像假药厂的弄倒了真药厂的。
二者的区别在于前缀的目的。
匈牙利系统命名法的前缀是为了说明变量的系统属性,比如类型。
String strName; //str表示这个变量是字符串
匈牙利应用命名法的前缀是为了说明变量的应用属性或业务属性。
String dogName,manName; //dog表示这个string是狗的名字。
系统命名法在从某种程度上来说是冗余的。
应用命名法却能够使代码的错误更容易被发现。
我们假设有一个生死薄系统,记载世上生物的轮回问题。它将每一个生物保持为一个对象的实例,里面有一个数据字段为name。
现在我们要把进行转世操作的一部分,以下是系统命名法的示例。
strName = dog.name //some op man.name = strName
上列代码要把人名赋值给狗,我们假设这在系统中是不允许的,会导致错误。但它在编译上却没有问题,如果说你把一个string赋值给一个string会导致编译错误的话,我们只能认为编译器今天心情不太好。
诚然,如果你是个认真的程序员,你好好查看整个过程的代码,可以看出这个strName到底是人名还是狗名,这里应不应该直接进行赋值操作。但是懒惰的程序员可能会想,能不能不去看那堆意大利面,直接从一行代码中看出不妥。
于是,匈牙利应用命名法出场了,它将代码改成这样
dogName = dog.name; //some op man.name = dogName;
“嘿,朋友,我不想要一个狗名字。”事情就会变成这样。
当然,编译器依然心情很好,不会给你报出什么错误来。但是你还有xlint,你可以设定一种规则不允许不同名字之间乱伦式的互赋值。
你应该把代码改成这样。
dogName = dog.name; manName = manFormDog(dogName); man.name = manName;
世界就和谐了,这只狗开开心心(可能也不是太开心,做人并不比做狗好。)转世为人。
现实的例子
一个留言本程序
留言本的主要工作就是把用户的输入显示出来,它任劳任怨地工作,如实地显示客户的留言。却有可能被别有用心的龌龊人士利用,比如输入特定的脚本,让服务器做一个特定的事。
这就意味着你在后面编程时必须时刻紧记一个原则:用户的输入是不安全的,永远不要把它们原样输出。
“但是这很累,”你说,“用户的留言在后台还要过不少地方,我还要考虑正常的业务流程,不想时刻绷着这么一条筋。”
于是应用命名法从天而降,像“威猛先生来了!”,你可以把用户的输入保存在一个String中,变量名用us前缀,代表“unsafe”,它可以在后台游弋,游来游去可能还都是us,只有经过特定的某几个方法才能变成"s"(safe)。
这样,你就不会要时盯着某个变量,看它到底安不安全。当你需要将它输出的时候,不用管它之前到底被怎么处理过,如果看到它的前缀是"s",“嗯,祝旅程愉快。”如果是"us",“啊,对不起,请打开包来检查一下。”