18.1 使代码更易于理解的东西

使代码易于理解的两个最重要的技术已经在前面的章节中讨论过了。第一个是选择好的名称(第14章)。精确而有意义的名称可以阐明代码的行为,减少对文档的需求。如果名称模糊不清,那么读者将不得不通读代码,以推断出被命名实体的含义;这既费时又容易出错。第二个技巧是一致性(第17章)。如果类似的事情总是以类似的方式完成,那么读者就可以识别出他们以前见过的模式,并立即得出(安全的)结论,而无需详细分析代码。

下面是一些其他的通用技术,可以使代码更加明显。

明智地使用空白。代码的格式化方式可以影响它的易懂程度。考虑一下下面的参数文档,其中的空白已经被挤掉了:

/** 
 * ...
 * @param numThreads The number of threads that this manager should
 * spin up in order to manage ongoing connections. The MessageManager
 * spins up at least one thread for every open connection, so this
 * should be at least equal to the number of connections you expect
 * to be open at once. This should be a multiple of that number if
 * you expect to send a lot of messages in a short amount of time.
 * @param handler Used as a callback in order to handle incoming
 * messages on this MessageManager's open connections. See
 * {@code MessageHandler} and {@code handleMessage} for details.
 */

很难看到一个参数的文档在哪里结束,下一个参数在哪里开始。甚至不知道有多少个参数,或者它们的名字是什么。如果增加一点空白,结构就会突然变得清晰,文档也会更容易浏览:

/** 
* @param numThreads
*          The number of threads that this manager should spin up in
*          order to manage ongoing connections. The MessageManager spins
*          up at least one thread for every open connection, so this
*          should be at least equal to the number of connections you
*          expect to be open at once. This should be a multiple of that
*          number if you expect to send a lot of messages in a short
*          amount of time.
* @param handler
*          Used as a callback in order to handle incoming messages on
*          this MessageManager's open connections. See
*          {@code MessageHandler} and {@code handleMessage} for details.
*/

空行对于分隔一个方法中的主要代码块也很有用,比如下面的例子。

void* Buffer::allocAux(size_t numBytes) 
{
    // Round up the length to a multiple of 8 bytes, to ensure alignment.
    uint32_t numBytes32 = (downCast<uint32_t>(numBytes) + 7) & ~0x7; 
    assert(numBytes32 != 0);
    
    // If there is enough memory at firstAvailable, use that. Work down
    // from the top, because this memory is guaranteed to be aligned
    // (memory at the bottom may have been used for variable-size chunks).
    if (availableLength >= numBytes32) {
       availableLength -= numBytes32;
       return firstAvailable + availableLength;
    }
    
    // Next, see if there is extra space at the end of the last chunk.
    if (extraAppendBytes >= numBytes32) {
       extraAppendBytes -= numBytes32;
       return lastChunk->data + lastChunk->length + extraAppendBytes;
    }
    
    // Must create a new space allocation; allocate space within it.
    uint32_t allocatedLength;
    firstAvailable = getNewAllocation(numBytes32, &allocatedLength);
    availableLength = allocatedLength numBytes32;
    return firstAvailable + availableLength;
}

如果每个空行后的第一行是描述下一个代码块的注释,这种方法就特别有效:空行使注释更加明显。

语句中的空白有助于阐明语句的结构。比较以下两条语句,其中一条有空白,一条没有。

for(int pass=1;pass>=0&&!empty;pass--) {

for (int pass = 1; pass >= 0 && !empty; pass--) {

注释。有时无法避免不易于理解的代码。当这种情况发生时,重要的是使用注释来弥补所缺的信息。要做好这一点,你必须把自己放在读者的位置上,弄清楚什么东西可能会使他们感到困惑,什么信息可以消除这种困惑。下一节将介绍几个例子。

Last updated