摘要:程序失敗時,很難確定錯誤的位置。它保護客戶免受單位工作細節的影響。將前提條件放在中,并將后置條件放入和。涉及可變對象的契約現在取決于每個引用可變對象的每個人的良好行為。設計規約按規約分類比較規約它是如何確定性的。
大綱
1.編程語言中的功能/方法
2.規約:便于交流的編程,為什么需要規約
行為等同規約結構:前提條件和后條件測試和驗證規約
3.設計規約分類規約圖表規約質量規約
4.總結
方法:構建模塊
大型項目由小型方法構建?
方法可以多帶帶開發,測試和重復使用
方法的用戶不需要知道它是如何工作的 - 這被稱為“抽象”
注意:調用方法時參數類型不匹配 - 靜態檢查
返回值類型是否匹配,也在靜態類型檢查階段完成
(1)編程中的文檔
Java API文檔:一個例子
類層次結構和實現的接口列表。?
直接子類,并為接口實現類。?
類的描述?
構建思想?
方法摘要列出了我們可以調用的所有方法
每個方法和構造函數的詳細描述
方法簽名:我們看到返回類型,方法名稱和參數。 我們也看到例外。 目前,這些通常意味著該方法可能遇到的錯誤。
完整的描述。
參數:方法參數的描述。
以及該方法返回的描述。
記錄假設
向下寫入變量的類型記錄了一個關于它的假設:例如,此變量將始終引用一個整數。
Java實際上在編譯時檢查了這個假設,并保證在你的程序中沒有地方違反了這個假設。
聲明一個變量final也是一種形式的文檔,聲明該變量在初始賦值后永遠不會改變。
Java也會靜態地檢查它。
如何函數/方法的假設?
便于交流的編程
為什么我們需要寫下我們的假設?
因為編程充滿了它們,如果我們不寫下它們,我們將不會記住它們,而其他需要閱讀或更改我們程序的人將不會知道它們。 他們必須猜測。
程序必須記住兩個目標:
與電腦交流。 首先說服編譯器你的程序是合理的 - 語法正確和類型正確。 然后讓邏輯正確,以便在運行時提供正確的結果。
與其他人溝通。 使程序易于理解,以便在有人修復,改進或未來適應時,他們可以這樣做。
黑客與工程
黑客往往以肆無忌憚的樂觀為標志
不好:在測試任何代碼之前先寫很多代碼
不好:把所有的細節都留在腦海中,假設你會永遠記住它們,而不是寫在你的代碼中
不好:假設錯誤不存在或者很容易找到并修復
但軟件工程不是黑客行為。 工程師是悲觀主義者:
好:一次寫一點,隨時測試(第7章中的測試優先編程)。
好:記錄你的代碼依賴的假設
好:捍衛你的代碼免受愚蠢 - 尤其是你自己的!
靜態檢查有助于此
(2)規約和契約(方法)
規約(或稱為契約)
規約是團隊合作的關鍵。 沒有規約就不可能委托實施方法的責任。
規約作為一種契約:實施者負責滿足契約,而使用該方法的客戶可以依賴契約。
說明方法和調用者的責任
定義實現的正確含義
規約對雙方都有要求:當規約有先決條件時,客戶也有責任。
如果你在這個時間表上支付了這筆款項......
我將用下面的詳細規約來構建一個
有些契約有不履行的補救措施
為什么規約?
現實:
程序中最常見的錯誤是由于對兩段代碼之間的接口行為的誤解而產生的。
盡管每個程序員都有規約說明,但并不是所有的程序員都把它們寫下來。 因此,團隊中的不同程序員有不同的規約。
程序失敗時,很難確定錯誤的位置。
優點:
代碼中的精確規約讓您分攤代碼片段的責備,并且可以免除您在修復應該去的地方令人費解的痛苦。
規約對于一個方法的客戶來說是很好的,因為他們不需要閱讀代碼。
規約對于方法的實現者來說是很好的,因為他們給了實現者自由地改變實現而不告訴客戶。
規約也可以使碼代碼更快。
契約充當客戶和實施者之間的防火墻。
它保護客戶免受單位工作細節的影響。
它將執行器從單元使用的細節中屏蔽掉。
這種防火墻會導致解耦,允許單元的代碼和客戶端的代碼獨立更改,只要這些更改符合規約。
解耦,不需要了解具體實現
對象與其用戶之間的協議
方法簽名(型號規約)
功能和正確性預期
性能預期性能?
該方法做了什么,而不是如何做
接口(API),不是實現
(3)行為等價性
要確定行為等同性,問題是我們是否可以用另一個實現替代另一個實現
等價的概念在客戶眼中。
為了使一個實現替代另一個實現成為可能,并且知道何時可以接受,我們需要一個規約來說明客戶端依賴于什么
注意:規約不應該談論方法類的局部變量或方法類的私有字段。
(4)規約結構:前提條件和后置條件
一個方法的規約由幾個子句組成:
先決條件,由關鍵字require表示
后置條件,由關鍵字效果表示
特殊行為:如果違反先決條件,會發生什么?
先決條件是客戶(即方法的調用者)的義務。 這是調用方法的狀態。
后置條件是該方法實施者的義務。
如果前提條件適用于調用狀態,則該方法必須遵守后置條件,方法是返回適當的值,拋出指定的異常,修改或不修改對象等等。
整體結構是一個合乎邏輯的含義:如果在調用方法時前提條件成立,則在方法完成時必須保持后置條件。
如果在調用方法時前提條件不成立,則實現不受后置條件的限制。
可以自由地做任何事情,包括不終止,拋出異常,返回任意結果,進行任意修改等。
Java中的規約
Java的靜態類型聲明實際上是方法的前提條件和后置條件的一部分,該方法是編譯器自動檢查和執行的一部分。
靜態檢查
契約的其余部分必須在該方法之前的評論中進行描述,并且通常取決于人類對其進行檢查并予以保證。
參數由@param子句描述,結果由@return和@throws子句描述。
將前提條件放在@param中,并將后置條件放入@return和@throws。
可變方法的規約
如果效應沒有明確說明輸入可以被突變,那么我們假設輸入的突變是隱式地被禁止的。
幾乎所有的程序員都會承擔同樣的事情。 驚喜突變導致可怕的錯誤。
慣例:
除非另有說明,否則不允許突變。
沒有突變的投入
可變對象可以使簡單的規約/合約非常復雜
可變對象降低了可變性
可變對象使簡單的合約變得復雜
對同一個可變對象(對象的別名)的多次引用可能意味著程序中的多個地方 - 可能相當分散 - 依靠該對象保持一致。
按照規約說明,契約不能再在一個地方執行,例如, 一個類的客戶和一個類的實施者之間。
涉及可變對象的契約現在取決于每個引用可變對象的每個人的良好行為。
作為這種非本地契約現象的一個癥狀,考慮Java集合類,這些類通常記錄在客戶端和實現者之間的非常明確的契約中。
嘗試找到它在客戶端記錄關鍵要求的位置,以便在迭代時無法修改集合。
對這樣的全局屬性進行推理的需要使得理解難度更大,并且對可變數據結構的程序的正確性有信心。
我們仍然必須這樣做 - 為了性能和便利性 - 但是為了這樣做,我們在bug安全方面付出了巨大的代價。
可變對象降低了可變性
可變對象使得客戶端和實現者之間的契約更加復雜,并且減少了客戶端和實現者改變的自由。
換句話說,使用允許更改的對象會使代碼難以改變。
(5)*測試和驗證規約
正式契約規約
Java建模語言(JML)
這是一個有優勢的理論方法
運行時檢查自動生成
正式驗證的依據
自動分析工具
缺點
需要很多工作
在大的不切實際
行為的某些方面不符合正式規約
文本說明 - Javadoc
實用方法
記錄每個參數,返回值,每個異常(選中和未選中),該方法執行的操作,包括目的,副作用,任何線程安全問題,任何性能問題。
不要記錄實施細節
語義正確性遵守契約
編譯器確保類型正確(靜態類型檢查)
防止許多運行時錯誤,例如“未找到方法”和“無法將布爾值添加到int”
靜態分析工具(如FindBugs)可以識別許多常見問題(錯誤模式)
例如:覆蓋equals而不覆蓋hashCode
但是,如何確保語義的正確性?
正式驗證
使用數學方法證明正式規約的正確性?
正式證明一個實現的所有可能的執行符合規約?
手動努力; 部分自動化; 不能自動確定
測試
使用受控環境中的選定輸入執行程序?
目標
顯示錯誤,因此可以修復(主要目標)
評估質量
明確說明書,文件
黑盒測試:以獨立于實現的方式檢查測試的程序是否遵循指定的規約。
設計規約(1)按規約分類
比較規約
它是如何確定性的。 該規約是否僅為給定輸入定義了單個可能的輸出,或允許實現者從一組合法輸出中進行選擇?
它是如何聲明的。 規約是否只是表征輸出的結果,還是明確說明如何計算輸出?
它有多強大。 規約是否只有一小部分法律實施或一大套?
“什么使一些規約比其他規約更好?”
如何比較兩種規約的行為來決定用新規約替換舊規約是否安全?
規約S2強于或等于規約S1如果
S2的先決條件弱于或等于S1
對于滿足S1的先決條件的狀態,S2的后置條件強于或等于S1。
那么滿足S2的實現也可以用來滿足S1,在程序中用S2代替S1是安全的。
規則:
削弱先決條件:減少對客戶的要求永遠不會讓他們感到不安。
加強后續條件,這意味著做出更多的承諾。
如果S3既不強于也不弱于S1,則規約可能會重疊(因此存在僅滿足S1,僅S3,以及S1和S3的實現)或者可能不相交。
在這兩種情況下,S1和S3都是無法比較的。
(2)圖表規約
這個空間中的每個點代表一個方法實現。
規約在所有可能的實現的空間中定義了一個區域。
一個給定的實現要么按照規約行事,要滿足前置條件 - 隱含 - 后置契約(它在區域內),或者不(在區域外)。
實現者可以自由地在規約中移動,更改代碼而不用擔心會破壞客戶端。
這對于實現者能夠提高其算法的性能,代碼的清晰度或者在發現錯誤時改變他們的方法等而言是至關重要的。
客戶不知道他們會得到哪些實現。
他們必須尊重規約,但也有自由改變他們如何使用實現而不用擔心會突然中斷。
當S2比S1強時,它在此圖中定義了一個較小的區域。
較弱的規約定義了一個更大的區域。
強化實施者的后置條件意味著他們自由度較低,對產出的要求更強。
弱化前提意味著:實現必須處理先前被規約排除的新輸入。
(3)設計好的規約
規約的質量
什么是一個好方法? 設計方法意味著主要編寫一個規約。
關于規約的形式:它顯然應該簡潔,清晰,結構良好,以便閱讀。
然而,規約的內容很難規定。 沒有一個可靠的規則,但有一些有用的指導方針。
規約應該是連貫的(內聚的)
該規約不應該有很多不同的情況。 冗長的參數列表,深層嵌套的if語句和布爾型標志都是麻煩的跡象。
除了可怕地使用全局變量和打印而不是返回之外,規約不是一致的 - 它執行兩個不同的事情,計算單詞并找出最長的單詞。
調用的結果應該是信息豐富的
如果返回null,則無法確定密鑰是否先前未綁定,或者實際上是否綁定為null。這不是一個很好的設計,因為返回值是無用的,除非您確定沒有插入null。
規約應該足夠強大
規約應給予客戶在一般情況下足夠強大的保證 - 它需要滿足其基本要求。 - 在規定特殊情況時,我們必須格外小心,確保它們不會破壞本來是有用的方法。例如,對于一個不合理的論證拋出異常,但允許任意的突變是沒有意義的,因為客戶端將無法確定實際發生了什么樣的突變。
規約也應該足夠薄弱
這是一個不好的規約。
它缺少重要的細節:打開閱讀或寫作文件? 它是否已經存在或被創建?
它太強大了,因為它無法保證打開文件。 它運行的過程可能缺少打開文件的權限,或者文件系統可能存在一些超出程序控制范圍的問題。相反,說明書應該說更弱一些:它試圖打開一個文件,如果成功,文件具有某些屬性。
規約應該使用抽象類型
用抽象類型編寫我們的規約為客戶和實現者提供了更多的自由。
在Java中,這通常意味著使用接口類型,如Map或Reader,而不是像HashMap或FileReader這樣的特定實現類型。
像列表或集合這樣的抽象概念
特定的實現像ArrayList或HashSet。
這強制客戶端傳入一個ArrayList,并強制實現返回一個ArrayList,即使可能存在他們希望使用的替代List實現。
先決條件還是后置條件?
是否使用前提條件,如果是,則在繼續之前,方法代碼是否應該嘗試確保先決條件已滿足?
對于程序員:
前提條件最常見的用法是要求提供一個屬性,因為該方法檢查該屬性會很困難或昂貴。
如果檢查一個條件會使方法變得難以接受,那么通常需要一個先決條件。
對用戶而言:
一個不平凡的先決條件會給客戶帶來不便,因為他們必須確保他們不會以不良狀態調用該方法(違反前提條件); 如果他們這樣做,沒有可預測的方法來從錯誤中恢復。
所以方法的用戶不喜歡先決條件。
因此,Java API類傾向于指定(作為后置條件),當參數不合適時,它們會拋出未經檢查的異常。
這使得在調用者代碼中找到導致傳遞錯誤參數的錯誤或不正確的假設更容易。
通常情況下,盡可能靠近錯誤的地點快速失敗,而不是讓糟糕的價值觀通過遠離其原始原因的程序傳播。
關鍵因素是檢查的費用(編寫和執行代碼)以及方法的范圍。
如果只在類本地調用,則可以通過仔細檢查調用該方法的所有類來解決前提條件。
如果該方法是公開的,并且被其他開發人員使用,那么使用前提條件將不太明智。 相反,像Java API類一樣,您應該拋出一個異常。
總結
規約作為程序實現者與其客戶之間的關鍵防火墻。
它使得多帶帶的開發成為可能:客戶端可以自由地編寫使用該過程的代碼,而無需查看其源代碼,并且實現者可以自由地編寫實現該過程的代碼而不知道它將如何使用。
減少錯誤保證安全
一個好的規約清楚地記錄了客戶和實施者依賴的相互假設。錯誤通常來自界面上的分歧,并且規約的存在會降低這一點。
在你的規約中使用機器檢查的語言特性,比如靜態類型和異常,而不僅僅是一個人類可讀的評論,可以更多地減少錯誤。容易理解
一個簡短的規約比實現本身更容易理解,并且使其他人不必閱讀代碼。
準備好改變
規約在代碼的不同部分之間建立契約,允許這些部分獨立更改,只要它們繼續滿足合同的要求。
聲明性規約在實踐中是最有用的。
先決條件(削弱了規約)使客戶的生活更加艱難,但明智地應用它們是軟件設計師的重要工具,允許實施者做出必要的假設。
減少錯誤保證安全
沒有規約,即使是我們程序中任何部分的細微變化,都可能成為敲打整個事情的尖端多米諾骨牌。
良好的結構,一致的規約最大限度地減少了誤解,并最大限度地提高了我們在靜態檢查,謹慎推理,測試和代碼審查的幫助下編寫正確代碼的能力。
容易理解
寫得很好的聲明性規約意味著客戶端不必閱讀或理解代碼。
準備好改變
適當的規約賦予實現者自由,適當的強壯規約賦予客戶自由。
我們甚至可以自己改變規約,而不必重新審視每個地方的使用情況,只要我們只是加強它們:削弱先決條件并加強后置條件。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71328.html
摘要:抽象數據類型的多個不同表示可以共存于同一個程序中,作為實現接口的不同類。封裝和信息隱藏信息隱藏將精心設計的模塊與不好的模塊區分開來的唯一最重要的因素是其隱藏內部數據和其他模塊的其他實施細節的程度。 大綱 面向對象的標準基本概念:對象,類,屬性,方法和接口OOP的獨特功能 封裝和信息隱藏 繼承和重寫 多態性,子類型和重載 靜態與動態分派 Java中一些重要的Object方法設計好的類面向...
摘要:抽象函數引發的關系是等價關系。所以當且僅當通過調用抽象數據類型的任何操作不能區分它們時,兩個對象是相等的。必須為每個抽象數據類型適當地定義操作。一般來說,在面向對象編程中使用是一種陋習。 大綱 什么是等價性?為什么要討論等價性?三種等價性的方式==與equals()不可變類型的等價性對象契約可變類型的等價性自動包裝和等價性 什么是等價性?為什么要討論等價性? ADT上的相等操作 ADT...
摘要:所有變量的類型在編譯時已知在程序運行之前,因此編譯器也可以推導出所有表達式的類型。像變量的類型一樣,這些聲明是重要的文檔,對代碼讀者很有用,并由編譯器進行靜態檢查。對象類型的值對象類型的值是由其類型標記的圓。 大綱 1.編程語言中的數據類型2.靜態與動態數據類型3.類型檢查4.易變性和不變性5.快照圖6.復雜的數據類型:數組和集合7.有用的不可變類型8.空引用9.總結 編程語言中的數據...
摘要:抽象工廠模式將具有共同主題的對象工廠分組。對可重用性和可維護性設計模式的高層考慮創造性模式工廠方法模式也稱為虛擬構造器意圖定義一個用于創建對象的接口,但讓子類決定實例化哪個類。 大綱 創造性模式 工廠方法模式創建對象而不指定要創建的確切類。 抽象工廠模式將具有共同主題的對象工廠分組。 Builder模式通過分離構造和表示來構造復雜的對象。 結構模式 Bridge將抽象從其實現中分...
閱讀 1397·2021-11-24 09:39
閱讀 3687·2021-11-24 09:39
閱讀 1859·2021-11-16 11:54
閱讀 1463·2021-09-30 09:47
閱讀 1712·2021-09-26 10:16
閱讀 2342·2021-09-22 15:33
閱讀 1453·2021-09-14 18:01
閱讀 2435·2021-09-07 09:59