选择好的标识符名称

Ken*_*ran 8 naming-conventions

好的,所以你可以阅读关于标识符命名的指导原则,直到你脸色发青蓝......骆驼的情况下,pascal的情况下,让它们描述性......但它们无法帮助你真正选择给定的最佳名称应用领域.

最容易选择(恕我直言)是一个或两个单词的名词组:

  • 报名表
  • 雇员
  • WidgetCollection

但并不是每个类都整齐地适合一个名词,所以我看到很多人通过在它们的末尾添加-er将动词变为名词:

  • 客户经理
  • RecordCounter
  • ProcessRunner

我看到这个问题的最大问题是很多时候他们都很模糊......特别是经理.究竟是什么管理?

所以我的问题是你如何为一个班级选择一个好名字?"好",我的意思是内容丰富,毫不含糊.

我知道我知道.几乎每个现代IDE都内置了重构支持,您可以更改名称而不必睁眼,那么重点是什么?一个选择不当的名字会混淆和误导任何偶然发现它的人,直到它被重命名为止,这仍然是一个有效的问题.

有关

命名类的最佳方法是什么?

Ken*_*ran 9

我一直在阅读罗伯特·C·马丁的" 清洁代码",并且还没有从第17章开始阅读这一部分,但我认为它最接近于回答这个问题.

N1:选择描述性名称

选择名字不要太快.确保名称是描述性的.请记住,随着软件的发展,意义往往会不断变化,因此经常重新评估您选择的名称的适当性.这不仅仅是一种"感觉良好"的建议.软件中的名称占软件可读性的90%.你需要花时间明智地选择它们并使它们保持相关性.名字太重要了,不能随意对待.请考虑以下代码.它有什么作用?如果我向你展示精选名字的代码,它对你来说将是非常有意义的,但就像这样,它只是一个符号和魔术数字的大杂烩.

public int x() {
    int q = 0;
    int z = 0;
    for (int kk = 0; kk < 10; kk++) {
        if (l[z] == 10)
        {
            q += 10 + (l[z + 1] + l[z + 2]);
            z += 1;
        }
        else if (l[z] + l[z + 1] == 10)
        {
            q += 10 + l[z + 2];
            z += 2;
        } else {
            q += l[z] + l[z + 1];
            z += 2;
        }
    }
    return q;
}
Run Code Online (Sandbox Code Playgroud)

这是代码应该写的方式.这个片段实际上不如上面那个完整.然而,您可以立即推断它正在尝试做什么,并且您很可能根据推断的含义编写缺失的函数.神奇的数字不再是魔术,算法的结构具有引人注目的描述性.

public int score() {
    int score = 0;
    int frame = 0;
    for (int frameNumber = 0; frameNumber < 10; frameNumber++) {
        if (isStrike(frame)) {
            score += 10 + nextTwoBallsForStrike(frame);
            frame += 1;
        } else if (isSpare(frame)) {
            score += 10 + nextBallForSpare(frame);
            frame += 2;
        } else {
            score += twoBallsInFrame(frame);
            frame += 2;
        }
    }
    return score;
}
Run Code Online (Sandbox Code Playgroud)

精心选择的名称的强大之处在于它们通过描述重载代码的结构.这种重载设置了读者对模块中其他功能的期望.您可以通过查看上面的代码来推断isStrike()的实现 .当您阅读isStrike 方法时,它将"非常符合您的预期".

private boolean isStrike(int frame) {
    return rolls[frame] == 10;
}
Run Code Online (Sandbox Code Playgroud)

N2:在适当的抽象级别选择名称

不要选择沟通实施的名称; 选择名称反映您正在工作的类或功能的抽象级别.这很难做到.同样,人们在混合抽象层次方面也非常擅长.每次对代码进行传递时,您可能会发现一些命名为太低级别的变量.您应该利用这个机会在找到它们时更改这些名称.使代码可读需要致力于持续改进.考虑下面的调制解调器 界面:

public interface Modem {
    boolean dial(String phoneNumber);
    boolean disconnect();
    boolean send(char c);
    char recv();
    String getConnectedPhoneNumber();
}
Run Code Online (Sandbox Code Playgroud)

起初看起来很好.这些功能似乎都合适.实际上,对于许多应用程序而言.但现在考虑一个应用程序,其中一些调制解调器没有通过拨号连接.相反,它们通过将它们硬连接在一起而永久连接(想想现在为大多数家庭提供互联网接入的电缆调制解调器).也许有些是通过USB连接向交换机发送端口号来连接的.很明显,电话号码的概念处于错误的抽象层次.此方案的更好的命名策略可能是:

public interface Modem {
    boolean connect(String connectionLocator);
    boolean disconnect();
    boolean send(char c);
    char recv();
    String getConnectedLocator();
}
Run Code Online (Sandbox Code Playgroud)

现在名字没有对电话号码做出任何承诺.它们仍可用于电话号码,或者可用于任何其他类型的连接策略.

N3:尽可能使用标准命名法

如果名称基于现有约定或用法,则更容易理解.例如,如果您使用的是DECORATOR模式,则应在装饰类的名称中使用Decorator一词.例如, AutoHangupModemDecorator可能是装饰调制解调器的类的名称,该类 能够在会话结束时自动挂起.模式只是一种标准.例如,在Java中,将对象转换为字符串表示的函数通常命名为 toString.遵循这些惯例比制造自己的惯例更好.团队通常会为特定项目创建自己的标准名称系统.埃里克埃文斯称这是该项目无处不在的语言.您的代码应广泛使用此语言中的术语.简而言之,您可以越多地使用与项目相关的特殊含义重载的名称,读者就越容易知道您的代码在谈论什么.

N4:明确的名称

选择使函数或变量的工作明确无误的名称.考虑一下FitNesse的这个例子:

private String doRename() throws Exception
{
    if(refactorReferences)
        renameReferences();
    renamePage();
    pathToRename.removeNameFromEnd();
    pathToRename.addNameToEnd(newName);
    return PathParser.render(pathToRename);
}
Run Code Online (Sandbox Code Playgroud)

除了广义和含糊的术语之外,这个函数的名称并没有说明函数的作用.在名为doRename的函数中有一个名为renamePage的函数,强调了这一点.这些名称告诉你两个函数之间的区别是什么?没有.该函数的更好名称是 renamePageAndOptionallyAllReferences.这可能看起来很长,而且它只是从模块中的一个地方调用,因此它的解释值超过了长度.

N5:长名称使用长名称

名称的长度应与范围的长度相关.对于小范围,您可以使用非常短的变量名称,但对于大范围,您应该使用更长的名称.如果它们的范围是五行,那么像ij这样的变量名称 就可以了.考虑旧标准"保龄球游戏"中的这个片段:

private void rollMany(int n, int pins)
{
    for (int i=0; i<n; i++)
        g.roll(pins);
}
Run Code Online (Sandbox Code Playgroud)

这是非常清楚的,如果变量i被像rollCount这样恼人的东西所取代,那么 它将被混淆.另一方面,具有短名称的变量和函数在长距离上失去意义.因此,名称的范围越长,名称就越长,越精确.

N6:避免编码

名称不应使用类型或范围信息进行编码.诸如m_f之类的前缀在当今的环境中是无用的.此外,项目和/或子系统编码(例如 vis_(用于视觉成像系统))分散注意力并且是多余的.同样,今天的环境提供所有信息,而不必破坏名称.保持您的名字免受匈牙利污染.

N7:名称应描述副作用

名称应描述函数,变量或类的所有内容.不要用名称隐藏副作用.不要使用简单的动词来描述不仅仅是简单动作的功能.例如,请考虑来自TestNG的此代码:

public ObjectOutputStream getOos() throws IOException {
    if (m_oos == null) {
        m_oos = new ObjectOutputStream(m_socket.getOutputStream());
    }
    return m_oos;
}
Run Code Online (Sandbox Code Playgroud)

这个功能比获得"oos"更多; 如果尚未创建"oos",它会创建它.因此,更好的名称可能是 createOrReturnOos.

  • 它是对[匈牙利符号](http://en.wikipedia.org/wiki/Hungarian_notation)的贬义,在现代IDE很容易检查类型信息之前,它曾经是一种常见的做法. (3认同)

Dre*_*ins 5

1) 不要缩写。仅当首字母缩略词符合行业标准(如 HTML)时才使用首字母缩略词。

2)在你的名字上保持一致。

3) 使用您的应用程序所在域中的术语。当想出一个名称时,假设在添加人们不熟悉的新名称时,您可以花费的子弹数量有限。

您可能会觉得您班级中的某些细微特征将它与“Foo”区分开来,并且由于这种细微差别而倾向于为它编造一些新概念。如果使用它的 80% 的人不会关心这种细微差别,请坚持使用已知术语。

4) 在大多数面向对象语言中,自动完成很重要。如果可能,第一个词应该是人们在探索命名空间时最有可能输入的词。其他人觉得用英文读好更重要,所以这有点值得商榷。