Code Complete II《軟體建構之道 2》#17 讀書心得與整理

  1. Code Complete II《軟體建構之道 2》#17 讀書心得與整理
    1. 第十七章 不常見的流程控制程式結冓 Unusual Control Structures
      1. 17.1 常式的多重回傳 Multiple Returns from a Routine
      2. 17.2 遞迴 Recursion
      3. 遞迴使用心得 Tips for Using Recursion
      4. 17.3 goto()語法 goto
        1. 反對goto的論點 The Argument Against gotos
        2. 支持goto的論點 The Argument for gotos
        3. 關於goto的假辨論 The Phony goto Debate
        4. goto與錯誤處理時 Error Processing and gotos
        5. goto與共享在else裡的代碼 gotos and Sharing Code in an else Clause
        6. goto的使用原則和心得 Summary of Guidelines for Using gotos
      5. 17.4 剖析不常見的流程控制程式結冓 Perspective on Unusual Control Structures

Code Complete II《軟體建構之道 2》#17 讀書心得與整理

原文連結: https://darkblack01.blogspot.com/2013/07/unusual-control-structures-17.html
移植時的最後更新日期: 2013-07-16T15:46:59.094+08:00

第十七章 不常見的流程控制程式結冓
Unusual Control Structures


17.1 常式的多重回傳
Multiple Returns from a Routine


在任何時候離開常式的方法。

return可以提高可讀性的時候
  1. 獲得解答,要立即回傳
  2. 不返回就得寫更多的程式碼跳過別的程式碼
使用防衛子句(guard clause)簡化複雜的錯誤處理
if (A is true)
if (B is true)
if (C is true)
//...
不如改成
if (A isn't true)
return notA;

if (B isn't true)
return notB;

if (C isn't true)
return notC;

//...everything is right
簡潔。但是,在產品代碼中,還須要更多的程式碼來處理這些not的狀況
if (A isn't true)
{
status = Error_A;
return notA;
}

if (B isn't true)
{
status = Error_B;
return notB;
}

if (C isn't true)
{
status = Error_C;
return notC;
}

//...everything is right
更可以讓有相關性的陳述式在一起(Scop縮小),提高可維護性和可讀性。

將每個常式的return數量降低
  • 在增加可讀性時增加數量
  • 在降低可讀性時降低數量


17.2 遞迴
Recursion


可產生優雅的解決方法,就用遞迴
用於小問題,產生簡單、正確的解決方案

遞迴使用心得
Tips for Using Recursion


留一個非遞迴的路徑,當作停止遞迴的出口
防止無限遞迴,考慮使用安全計數器,預防堆疊溢位
多常式遞迴,很危險,請保持在單一常式
使用new創造物件,不要讓它是auto創造出來。
不要使用遞迴運算階乘和數列的問題


17.3 goto()語法
goto


反對goto的論點
The Argument Against gotos

  • 含有goto的程式碼沒有品質
  • 邏輯結構無法利用排版凸顯
  • 編譯器無法最佳化

支持goto的論點
The Argument for gotos

  • goto使程式碼更快或更小
  • 減少重覆的程式碼

關於goto的假辨論
The Phony goto Debate


結論:即使明白所有可以避開goto的程式技巧,但有時候使用goto卻可以提高可讀性和可維護性

goto與錯誤處理時
Error Processing and gotos


goto版
errorState = FileStatus_Success
fileIndex = 0

While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )

fileIndex = fileIndex + 1

If Not ( FindFile( fileList( fileIndex ), fileToPurge ) )
Then
errorState = FileStatus_FileFindError
GoTo END_PROC
End If

If Not OpenFile( fileToPurge )
Then
errorState = FileStatus_FileOpenError
GoTo END_PROC
End If

If Not OverwriteFile( fileToPurge )
Then
errorState = FileStatus_FileOverwriteError
GoTo END_PROC
End If

If Erase( fileToPurge )
Then
errorState = FileStatus_FileEraseError
GoTo END_PROC
End If
End While

DeletePurgeFileList( fileList, numFilesToPurge )
深巢狀if版
errorState = FileStatus_Success
fileIndex = 0

While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )

fileIndex = fileIndex + 1

If FindFile( fileList( fileIndex ), fileToPurge )
Then
If OpenFile( fileToPurge )
Then
If OverwriteFile( fileToPurge )
Then
If Not Erase( fileToPurge )
Then
errorState = FileStatus_FileEraseError
End If
Else ' couldn\'t overwrite file'
errorState = FileStatus_FileOverwriteError
End If
Else ' couldn\'t open file'
errorState = FileStatus_FileOpenError
End If
Else ' couldn\'t find file'
errorState = FileStatus_FileFindError
End If
End While

DeletePurgeFileList( fileList, numFilesToPurge )
Status變數版
errorState = FileStatus_Success
fileIndex = 0

While ( fileIndex < numFilesToPurge ) And ( errorState = FileStatus_Success )

fileIndex = fileIndex + 1

If Not FindFile( fileList( fileIndex ), fileToPurge )
Then
errorState = FileStatus_FileFindError
End If

If ( errorState = FileStatus_Success )
Then
If Not OpenFile( fileToPurge )
Then
errorState = FileStatus_FileOpenError
End If
End If

If ( errorState = FileStatus_Success )
Then
If Not OverwriteFile( fileToPurge )
Then
errorState = FileStatus_FileOverwriteError
End If
End If

If ( errorState = FileStatus_Success )
Then
If Not Erase( fileToPurge ) Then
errorState = FileStatus_FileEraseError
End If
End If
End While

DeletePurgeFileList( fileList, numFilesToPurge )
try-finally版
Try
fileIndex = 0
While ( fileIndex < numFilesToPurge )
fileIndex = fileIndex + 1
FindFile( fileList( fileIndex ), fileToPurge )
OpenFile( fileToPurge )
OverwriteFile( fileToPurge )
Erase( fileToPurge )
Wend
Finally
DeletePurgeFileList( fileList, numFilesToPurge )
End Try

寫法  goto版 深巢狀if版 狀態變數版 try-finally版
goto語法 可避開 可避開 可避開
巢狀if的語法 可避開 可避開 可避開
其它 避開額外測試 產生複雜的程式碼 需加入額外測試 並不是每個語言都支援


goto與共享在else裡的代碼
gotos and Sharing Code in an else Clause


goto版
if ( statusOk ) {
if ( dataAvailable ) {
importantVariable = x;
goto MID_LOOP;
}
}
else {
importantVariable = GetValue();

MID_LOOP:

// lots of code
...
}
呼叫常式版
if ( statusOk )
{
if ( dataAvailable )
{
importantVariable = x;
DoLotsOfCode( importantVariable );
}
}
else
{
importantVariable = GetValue();
DoLotsOfCode( importantVariable );
}
重建條件式版
if ( ( statusOk && dataAvailable ) || !statusOk )
{
if ( statusOk && dataAvailable )
{
importantVariable = x;
}
else
{
importantVariable = GetValue();
}

// lots of code
...
}

goto的使用原則和心得
Summary of Guidelines for Using gotos


goto的使用與否取決於信仰。
goto()代表效率。

17.4 剖析不常見的流程控制程式結冓
Perspective on Unusual Control Structures