<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### Introduce Assertion(引入斷言) 某一段代碼需要對程序狀態(state)做出某種假設。 以assertion(斷言)明確表現這種假設。 ~~~ double getExpenseLimit() { // should have either expense limit or a primary project return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } ~~~ => ~~~ double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } ~~~ **動機(Motivation)** 常常會有這樣一段代碼:只有當某個條件為真時,該段代碼才能正常運行。例如「平方報計算」只對正值才能進行(譯注:這里沒考慮復數與虛數),又例如某個對象 可能假設其值域(fields)至少有一個不等于null。 這樣的假設通常并沒有在代碼中明確表現出來,你必須閱讀整個算法才能看出。有時程序員會以注釋寫出這樣的假設。而我要介紹的是一種更好的技術:使用assertion(斷言)明確標明這些假設。 assertion 是一個條件式,應該總是為真。如果它失敗,表示程序員犯了錯誤。因此assertion的失敗應該導致一個unchecked exception[7](不可控異常〕。Assertions 絕對不能被系統的其他部分使用。實際上程序最后成品往往將assertions 統統刪除。因此,標記「某些東西是個assertion」是很重要的。 [7]譯注:所謂unchecked exception 是指「未曾于函數簽名式(signature)中列出」的異常。 Assertions 可以作為交流與調試的輔助。在交流(溝通〕的角度上,assertions 可以幫助程序閱讀者理解代碼所做的假設;在調試的角度上,assertions 可以在距離「臭蟲」最近的地方抓住它們。當我編寫自我測試代碼的時候,我發現,assertions 在調試方面的幫助變得不那么重要了,但我仍然非常看重它們在交流方面的價值。 **作法(Mechanics)** 如果程序員不犯錯,assertions 就應該不會對系統運行造成任何影響,所以加入assertions 永遠不會影響程序的行為。 - 如果你發現代碼「假設某個條件始終(必須)為真],就加入一個assertion 明確說明這種情況。 - 你可以新建一個Assert class,用于處理各種情況下的assertions 。 注意,不要濫用assertions 。請不要使用它來檢查你「認為應該為真」的條件,請只使用它來檢查「一定必須為真」的條件。濫用assertions 可能會造成難以維護的重復邏輯。在一段邏輯中加入assertions 是有好處的,因為它迫使你重新考慮這段代 碼的約束條件。如果「不滿足這些約朿條件,程序也可以正常運行」,assertions 就不會帶給你任何幫助,只會把代碼變得混亂,并且有可能妨礙以后的修改。 你應該常常問自己:如果assertions 所指示的約束條件不能滿足,代碼是否仍能正常運行?如果可以,就把assertions 拿掉。 另外,還需要注意assertions 中的重復代碼。它們和其他任何地方的重復代碼一樣不好聞。你可以大膽使用Extract Method 去掉那些重復代碼。 **范例:(Example)** 下面是一個簡單例子:開支(經費)限制。后勤部門的員工每個月有固定的開支限額;業務部門的員工則按照項目的開支限額來控制自己的開支。一個員工可能沒有開支額度可用,也可能沒有參與項目,但兩者總得要有一個(否則就沒有經費可用 了)。在開支限額相關程序中,上述假設總是成立的,因此: ~~~ class Employee... private static final double NULL_EXPENSE = -1.0; private double _expenseLimit = NULL_EXPENSE; private Project _primaryProject; double getExpenseLimit() { return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } boolean withinLimit (double expenseAmount) { return (expenseAmount <= getExpenseLimit()); } ~~~ 這段代碼包含了一個明顯假設:任何員工要不就參與某個項目,要不就有個人開支限額。我們可以使用assertion 在代碼中更明確地指出這一點: ~~~ double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } ~~~ 這條assertion 不會改變程序的任何行為。另一方面,如果assertion中的條件不為真,我就會收到一個運行期異常:也許是在withinLimit() 函數中拋出一個空指針(null pointer)異常,也許是在Assert.isTrue() 函數中拋出一個運行期異常。有時assertion 可以幫助程序員找到臭蟲,因為它離出錯地點很近。但是,更多時候,assertion 的價值在于:幫助程序員理解代碼正確運行的必要條件。 我常對assertion 中的條件式使用Extract Method ,也許是為了將若干地方的重復碼提煉到同一個函數中,也許只是為了更清楚說明條件式的用途。 在Java 中使用assertions 有點麻煩:沒有一種簡單機制可以協助我們插入這東西[8]。 assertions 可被輕松拿掉,所以它們不可能影響最終成品的性能。編寫一個輔助類(例如Assert class)當然有所幫助,可惜的是assertions 參數中的任何表達式不論什么情況都一定會被執行一遍。阻止它的惟一辦法就是使用類似下面的手法: [8[譯注:J2SE1.4已經支持assert語句。 ~~~ double getExpenseLimit() { Assert.isTrue (Assert.ON && (_expenseLimit != NULL_EXPENSE || _primaryProject != null)); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } ~~~ 或者是這種手法: ~~~ double getExpenseLimit() { if (Assert.ON) Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } ~~~ 如果Assert.ON 是個常量,編譯器(譯注:而非運行期間)就會對它進行檢查; 如果它等于false ,就不再執行條件式后半段代碼。但是,加上這條語句實在有點丑陋,所以很多程序員寧可僅僅使用Assert.isTrue() 函數,然后在項目結束前以過濾程序濾掉使用assertions 的每一行代碼(可以使用Perl 之類的語言來編寫這樣 的過濾程序)。 Assert class應該有多個函數,函數名稱應該幫助程序員理解其功用。除了isTrue() 之外,你還可以為它加上equals() 和shouldNeverReachHere() 等函數。 # 章節十 簡化函數調用 在對象技術中,最重要的概念莫過于「接口」(interface)。容易被理解和被使用的接口,是開發良好面向對象軟件的關鍵。本章將介紹「使接口變得更簡潔易用」 的重構手法。 最簡單也最重要的一件事就是修改函數名稱。「名稱」是程序寫作者與閱讀者交流的關鍵工具。只要你能理解一段程序的功能,就應該大膽地使用Rename Method 將你所知道的東西傳達給其他人。另外,你也可以(并且應該)在適當時機修改變量名稱和class 名稱。不過,總體來說,「修改名稱」只是相對比較簡單 的文本替換功夫,所以我沒有為它們提供單獨的重構項目。 函數參數在「接口」之中扮演十分重要的角色。 Add Parameter 和Remove Parameter 都是很常見的重構手法。初始接觸面向對象技術的程序員往往使用很長的參數列(parameter lists),這在其他開發環境中是很典型的方式。但是, 使用對象技術,你可以保持參數列的簡短,以下有一些相關的重構可以幫助你縮短參數列。如果來自同一對象的數個值被當作參數傳遞,你可以運用 Preserve Whole Object 將它們替換為單一對象,從而縮短參數列。如果此前并不存在這樣一個對象,你可以運用Introduce Parameter Object將它創建出來。如果函數參數來自該函數可取用的一個對象,則可以使用 Replace Parameter with Method 避免傳遞參數。如果某些參數被用來在條件式中做選擇依據,你可以實施 Replace Parameter with Explicit Methods。另外,你還可以使用Parameterize Method 為數個相似函數添加參數,將它們合并到一起。 關于縮減參數列的重構手法,Doug Lea 對我提出了一個警告:并發編程(con-current programming)往往需要使用較長的參數列,因為這樣你可以保證傳遞給函數的參數都是不可被修改的,就像內置型對象和value object 一定地不可變。通常,你可以使用不可變對象(immutable object)取代這樣的長參數列,但另一方面你也必須對此類重構保持謹慎。 多年來我一直堅守一個很有價值的習慣:明確地將「修改對象狀態」的函數(修改函數,modifiers)和「查詢對象狀態」的函數(查詢函數,queries)分開設計。不知道多少次,我因為將這兩種函數混在一起而麻煩纏身;不知道多少次,我看到別 人也因為同樣的原因而遇到同樣的麻煩。因此,如果我看到這兩種函數混在一起, 我就使用 Separate Query from Modifier 將它們分開。 良好的接口只向用戶展現必須展現的東西。如果一個接口暴露了過多細節,你可以將不必要暴露的東西隱藏起來,從而改進接口的質量。毫無疑問,所有數據都應該隱藏起來(希望你不需要我來告訴你這一點),同時,所有可以隱藏的函數都應該被隱藏起來。進行重構時,你往往需要暫時暴露某些東西,最后再以 Hide Method 和Remove Setting Method 將它們隱藏起來。 構造函數(constructors)是Java 和C++ 中特別麻煩的一個東西,因為它強迫你必須知道「待建對象」屬于哪一個class ,而你往往并不需要知道這一點。你可以使用Replace Constructor with Factory Method 避免了解這「被迫了解的一點」。 轉型(casting)是Java 程序員心中另一處永遠的痛。你應該盡量使用Encapsulate Downcast 將「向下轉型動作」封裝隱藏起來,避免讓class 用戶做那種動作。 和許多現代編程語言一樣,Java 也有異常處理(exception-handing)機制,這使得錯誤處理(error handling)相對容易一些。不習慣使用異常的程序員,往往會以錯誤代碼(error code)表示程序遇到的麻煩。你可以使用Replace Error Code with Exception 來運用這些嶄新的異常特性。但有時候異常也并不是最合適的選擇,你應該實施Replace Exception with Test 先測試一番。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看