我一直在阅读 Robert C. Martin 的Clean Code,但我还没有从第 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;
}
这是代码应该是这样的
书面。这个sn-p其实少了
比上一个完整。然而你
可以立即推断出它是什么
试着去做,你可以非常
可能写缺少的功能
基于该推断的含义。这
魔术数字不再是魔术,而且
算法的结构是
令人信服的描述。
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;
}
精心挑选的名字的力量是
他们超载的结构
带有描述的代码。那
超载设置了读者的
对对方的期望
模块中的功能。你可以
推断执行
isStrike() 查看上面的代码。当您阅读 isStrike
方法,它将是“几乎什么
你期望的。”
private boolean isStrike(int frame) {
return rolls[frame] == 10;
}
N2:选择适当抽象级别的名称
不要选择能交流的名字
执行;选择名称
反映抽象层次
你正在工作的类或函数
中。这很难做到。再次,人们
只是太擅长混合水平
抽象。每次你做一个
传递您的代码,您可能会
找到一些名为的变量
太低的水平。你应该采取
有机会更改这些名称时
你找到他们。使代码可读
需要持续不断的奉献精神
改进。考虑 调制解调器
界面如下:
public interface Modem {
boolean dial(String phoneNumber);
boolean disconnect();
boolean send(char c);
char recv();
String getConnectedPhoneNumber();
}
起初这看起来不错。这
功能似乎都合适。
事实上,对于许多应用来说,它们
是。但是现在考虑一个应用程序
其中一些调制解调器未连接
通过拨号。相反,它们是连接的
通过硬接线永久
一起(想想电缆调制解调器
为大多数人提供 Internet 访问
现在的家)。也许有些是
通过发送端口号连接到
切换 USB 连接。
显然电话号码的概念是
在错误的抽象级别。一种
更好的命名策略
场景可能是:
public interface Modem {
boolean connect(String connectionLocator);
boolean disconnect();
boolean send(char c);
char recv();
String getConnectedLocator();
}
现在这些名字没有任何意义
关于电话号码的承诺。他们
仍可用于电话号码,
或者它们可以用于任何其他
一种连接策略。
N3:尽可能使用标准命名法
如果名字更容易理解
基于现有约定或
用法。例如,如果您正在使用
DECORATOR 模式,你应该使用
名称中的装饰器
装饰课。例如,
AutoHangupModemDecorator 可能是
装饰调制解调器的类的名称
具有自动挂起的能力
在会话结束时。模式
只是一种标准。在
例如,Java 中的函数
将对象转换为字符串
表示通常被命名为
toString。最好遵循
像这样的约定而不是发明
你自己。团队经常会发明
他们自己的标准名称系统
一个特定的项目。埃里克·埃文斯
将此称为无处不在
项目的语言。你的代码
应该使用此条款
语言广泛。简而言之,
更多你可以使用的名字
带有特殊含义的重载
与您的项目相关,
读者更容易知道
你的代码在说什么。
N4:明确的名称
选择能够发挥作用的名称
明确的函数或变量。
看看 FitNesse 的这个例子:
private String doRename() throws Exception
{
if(refactorReferences)
renameReferences();
renamePage();
pathToRename.removeNameFromEnd();
pathToRename.addNameToEnd(newName);
return PathParser.render(pathToRename);
}
这个函数的名字没有说
除了广泛的功能外,该功能的作用是什么
和模糊的术语。这强调了
有一个功能的事实
在函数中命名为 renamePage
命名为 doRename!名字说明了什么
你关于两者的区别
两个功能?没有。更好的名字
因为那个函数是
重命名PageAndOptionallyAllReferences。
这可能看起来很长,而且确实很长,但是
它只从一个地方调用
模块,所以它是解释值
超过长度。
N5:对长范围使用长名称
名字的长度应该是相关的
到范围的长度。你可以
对 tiny 使用非常短的变量名
范围,但对于大范围,你应该
使用更长的名称。变量名称如
i 和 j 如果他们的范围就好了
是五行长。考虑这个
sn-p 来自旧标准“保龄球
游戏”:
private void rollMany(int n, int pins)
{
for (int i=0; i<n; i++)
g.roll(pins);
}
这是非常清楚的,将是
如果变量 i 是混淆的
取而代之的是烦人的东西
滚动计数。另一方面,
变量和函数短
名字长期失去意义
距离。所以范围越长
名字越长越准确
名字应该是。
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;
}
这个函数的作用远不止 get
“oos”;如果它创建“oos”
尚未创建。因此,一个
更好的名字可能是
createOrReturnOos。