命名有两个目标:
当一个命名完成上面两个目标之后,其余的字符就是多余的了。下面是我在开发时的一些命名原则:
如果使用如Java之类的静态类型语言,开发者通常知道变量的类型。由于方法的实现一般都比较简短,所以即便是在查看一个需要推断才知道类型的本地变量,或者在code review等静态分析器不可用的情况下,我们也可以通过多看很少的几行代码就能知道变量的类型。
所以将类型说明加入到变量名中是多余的。我们应该舍弃匈牙利命名法,如下:
// 不好的: String nameString; DockableModelessWindow dockableModelessWindow; // 改进: String name; DockableModelessWindow window;
特别是对于集合来说,最好使用名词的复数形式来描述其内容,而不是使用名词的单数形式来描述。如果开发者更在乎集合中存储的内容, 那么变量命名应当反映这一点。
// 不好的: ListholidayDateList; Map employeeRoleHashMap; // 改进: List holidays; Map employeeRoles;
这一点也同样适用于方法的命名。方法名不需要描述它的参数及参数的类型——参数列表已经说明了这些。
// 不好的: mergeTableCells(Listcells) sortEventsUsingComparator(List events, Comparator comparator) // 改进: merge(List cells) sort(List events, Comparator comparator)
省略命名中不是用来消除歧义的单词
有些开发者倾向于将他们知道的有关这个变量的所有信息都塞到命名里。要记住,命名只是一个标识符:只是告诉你该变量是在哪定义的。并不是用来告诉阅读者所有他们想知道的有关这个对象的详细信息。这是定义应该做的事情的。 命名只是让你找到它的定义。
当我看到一个叫recentlyUpdatedAnnualSalesBid
(最近更新的全年销售投标)的标识符时,我会问:
上面任何一个问题的回答是“不存在”,就意味着命名中引入了无用的单词。
// 不好的: finalBattleMostDangerousBossMonster; weaklingFirstEncounterMonster; // 改进: boss; firstMonster;
当然,你可能会觉得这有一些过了。比如将第一个例子的标识符简化为bid,
会让人觉得有点模糊不清。但你可以放心大胆的这样做,如果在之后的开发中觉得该命名会造成冲突或不明确,可以添加些修饰词来完善它。反之,如果一开始就取了一个很长的命名,你是不可能在之后重新回来简化它的。
我可以在文章中使用”我”,因为读者都知道这是一篇由Bob Nystrom所做的博客。我蠢萌的脸就挂在那,我无需不停的说我的名字。写代码也是一样,类中的方法/属性和方法中的变量,都是存在在上下文中的,无需重复。
// Bad: class AnnualHolidaySale { int _annualSaleRebate; void promoteHolidaySale() { ... } } // Better: class AnnualHolidaySale { int _rebate; void promote() { ... } }
实际上,一个命名嵌套的层次越多, 它就有更多的相关的上下文,也就更简短。换句话说,一个变量的作用域越小,命名就越短。
我常常在许多游戏开发中看到包含无任何含义的单词的命名,一些开发者喜欢在命名中添加一些看起来有点严肃的单词。我猜可能他们觉得这样做可以让他们的代码显得重要,或者说让他们觉得自己更重要。
实际上,有一些词语并没有实际意义,只是一些套话。比如:data, state, amount, value, manager, engine, object, entity和instance。
一个好的命名能够在阅读者的脑海中描画出一幅图画。而将某变量命名为”manager”并不能向读者传达任何有关该变量是做什么的信息。它是用来做绩效评估的吗? 它是管理加薪的吗?
在命名时可以问一下自己,把这个单词去掉含义是不是不变?如果是,那就果断把它剔除吧~~
为了让大家了解以上的命名原则在实际中如何应用,这有个违法了以上所有原则的反例。这个例子和我实际上review过的一段代码一样令人心碎。。。。
// 好吃的比利时华夫饼 class DeliciousBelgianWaffleObject { void garnishDeliciousBelgianWaffleWithStrawberryList( ListstrawberryList) { ... } }
首先,通过参数列表我们可以知道方法是用来处理一个strawberry的列表,所以可以在方法命名中去掉:
class DeliciousBelgianWaffleObject { void garnishDeliciousBelgianWaffle( Liststrawberries) { ... } }
除非程序中还包含不好吃的比利时华夫饼或者其他国家的华夫饼,不然我们可以将这些无用的形容词去掉:
class WaffleObject { void garnishWaffle(Liststrawberries) { ... } }
方法是包含在WaffleObject
类中的,所以方法名中无需Waffle的说明:
class WaffleObject { void garnish(Liststrawberries) { ... } }
很明显它是一个对象,任何事物都是一个对象,这也就是传说中的“面向对象”的含义,所以命名中无需带有Object
:
class Waffle { void garnish(Liststrawberries) { ... } }
好了,这样看起来好多了。
以上就是我总结的相当简洁的命名原则。可能有些人会觉得无需在命名上耗费太多的精力,但我认为命名是开发过程中最基本的任务之一。
————————————————–我是萌萌哒分界线————————————————
感觉变量或者方法的命名,看似简单,实际很难,特别是想一个简洁明了、可读性高的命名。自己也经常用什么data
, xxxlist
来命名,作者说的挺对的,前者没什么意义,后者又有点啰嗦。不过对于集合类型的变量,统一用名词复数命名容易混淆。举个例子对于Apple这个类来说,可能存在List和Map两种集合类型的变量。个人觉得对List类型的变量可以采用名词复数来命名,Map类型的变量可以采用valueByKey格式来命名,比较容易区分。