日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

哈工大软件构造课程知识点总结(三)

發(fā)布時間:2023/12/20 编程问答 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 哈工大软件构造课程知识点总结(三) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

系列文章目錄

哈工大軟件構(gòu)造課程知識點總結(jié)(一)
哈工大軟件構(gòu)造課程知識點總結(jié)(二)
哈工大軟件構(gòu)造課程知識點總結(jié)(三)
哈工大軟件構(gòu)造課程知識點總結(jié)(四)
哈工大軟件構(gòu)造課程知識點總結(jié)(五)
哈工大軟件構(gòu)造課程知識點總結(jié)(六)


文章目錄

  • 系列文章目錄
  • 簡介
  • Chapter 5:Designing Specification
    • 規(guī)約簡要介紹
    • 行為等價性
    • 規(guī)約的設(shè)計
    • 規(guī)約的比較
    • 規(guī)約畫圖
    • 如何設(shè)計好的規(guī)約
  • Chapter 6:Abstract Data Type
    • 抽象數(shù)據(jù)類型相關(guān)概念
    • 設(shè)計抽象數(shù)據(jù)類型
    • 測試抽象數(shù)據(jù)類型
    • 表示獨立性
    • 表示不變性
    • 抽象函數(shù)
    • 表示不變性(RI)與抽象函數(shù)(AF)之間的關(guān)系
      • 表示泄露
    • 有益的可變性


簡介

此文章是2021春哈工大軟件構(gòu)造課程Chapter 5、Chapter 6的知識點總結(jié)。

Chapter 5:Designing Specification

規(guī)約簡要介紹

“方法”是程序的積木,可以被獨立開發(fā)、測試、復(fù)用。使用“方法”的客戶端,無需了解內(nèi)部的具體實現(xiàn),這就是“抽象” 的思想。
一個完整的方法應(yīng)包含規(guī)約實現(xiàn)兩大部分,如下圖示例:

代碼本身就蘊含著“設(shè)計決策”(如使用final關(guān)鍵字說明此變量不可變),但這遠(yuǎn)遠(yuǎn)不夠。我們需要注釋形式的“設(shè)計決策”(規(guī)約)以供自己和他人閱讀。

規(guī)約(spec)給程序員和用戶雙方都確定了責(zé)任,調(diào)用時雙方都要遵守。

規(guī)約的作用:

  • 隔離“變化”,無需通知客戶端——“防火墻”
  • 解耦,客戶端不需了解具體實現(xiàn)
  • 提高代碼效率


規(guī)約的內(nèi)容:

  • 輸入/輸出的數(shù)據(jù)類型
  • 方法的功能和正確性
  • 性能

只講“能做什么”,不講“如何實現(xiàn)”!

行為等價性

根據(jù)代碼的規(guī)約,站在客戶端視角看行為等價性。
例: 有以下兩個方法:

static int findFirst(int[] arr, int val) {for (int i = 0; i < arr.length; i++) {if (arr[i] == val)return i;}return arr.length; }static int findLast(int[] arr, int val) {for (int i = arr.length - 1; i >= 0; i--) {if (arr[i] == val)return i;}return -1; }

對于以下規(guī)約:

由于兩個函數(shù)都符合此規(guī)約,故此情況下它們等價。

規(guī)約的設(shè)計

前置條件(precondition):對客戶端的約束,客戶端使用方法時必須滿足的條件,使用關(guān)鍵詞requires表明。
后置條件(postcondition):對開發(fā)者的約束,方法結(jié)束時必須滿足的條件,使用關(guān)鍵詞effects表明。

  • 靜態(tài)類型聲明是一種規(guī)約,可據(jù)此進(jìn)行靜態(tài)類型檢查(static checking)
  • 方法前的注釋也是一種規(guī)約,但需人工判定其是否滿足

契約:如果前置條件滿足了,后置條件必須滿足;前置條件不滿足,則方法可做任何事情(最好還是處理一下,通過failing fast讓客戶端發(fā)現(xiàn)這一問題)。

規(guī)約具體設(shè)計規(guī)則:

  • 參數(shù)使用@param描述,結(jié)果使用@return、@throws描述
  • 如果可能,將前置條件寫入@param中,后置條件寫入@return和@throws中
  • 除非在后置條件中聲明過,否則方法內(nèi)部不應(yīng)該改變輸入?yún)?shù)
  • 盡量不設(shè)計修改輸入?yún)?shù)的規(guī)約,減少使用可變對象
  • 描述的功能要單一、簡單、易理解
  • 如果規(guī)約中需要提到“值”,只能使用抽象空間中的“值”(關(guān)聯(lián)Chapter 6)

一個具體的規(guī)約:

補充Chapter 2 黑盒測試部分:
測試用例不能依賴于具體實現(xiàn),而必須同客戶端一樣,遵守規(guī)約
出處:Chapter 5 課件 P46

規(guī)約的比較

可從規(guī)約的確定性、陳述性及強度入手進(jìn)行比較。
假如規(guī)約強度S2 >= S1,則有:

  • 前置條件S2比S1更弱或相同
  • 后置條件S2比S1更強或相同

較強的規(guī)約具有更放松的前置條件 + 更嚴(yán)格的后置條件

例:
(1)以下三個規(guī)約依次增強:

(2)以下兩個規(guī)約無法比較強度


相較于第一個規(guī)約,第二個的前置條件更弱了;但在滿足第一個規(guī)約的前置條件的情況下,第二個規(guī)約相較于第一個其后置條件也弱化了(沒有返回最低索引值)。

當(dāng)規(guī)約被增強時:

  • 可滿足規(guī)約的實現(xiàn)方式更少
  • 更多的用戶端可以使用
  • 實現(xiàn)者(開發(fā)者)的自由度更小,責(zé)任更重
  • 客戶端(使用者)責(zé)任更輕

規(guī)約畫圖

以find為例:

可以得到以下結(jié)論:

  • 某個具體實現(xiàn),若滿足規(guī)約,則落在其范圍內(nèi),否則,在其之外
  • 程序員可以在規(guī)約的范圍內(nèi)自由選擇實現(xiàn)方式,客戶端無需了解具體使用了哪個實現(xiàn)
  • 規(guī)約越強,對應(yīng)的區(qū)域越小

如何設(shè)計好的規(guī)約

  • 規(guī)約不應(yīng)太弱,也不能太強(權(quán)衡用戶使用與實現(xiàn)難度)
  • 在規(guī)約里使用抽象類型,可以給方法的實現(xiàn)體與客戶端更大的自由度
  • 是否使用前置條件取決于check的代價和方法的使用范圍

Chapter 6:Abstract Data Type

抽象數(shù)據(jù)類型相關(guān)概念

抽象數(shù)據(jù)類型(ADT)強調(diào)“作用于數(shù)據(jù)上的操作”,程序員和客戶端無需關(guān)心數(shù)據(jù)如何具體存儲的,只需設(shè)計/使用操作即可。

抽象數(shù)據(jù)類型的特性:

  • 可能發(fā)生表示泄露
  • 抽象函數(shù)(abstraction function) [AF]
  • 表示獨立性(representation independence) [RI]
  • 表示不變性(representation invariant)

抽象數(shù)據(jù)類型的操作分類:

  • 構(gòu)造器(creator):t* → T,可能實現(xiàn)為構(gòu)造函數(shù)或靜態(tài)函數(shù)(工廠方法)
  • 生產(chǎn)器(producer):T+, t* → T
  • 觀察器(observer):T+, t* → t
  • 變值器(mutator):T+, t* → void | t | T,通常返回void,也可返回非空(如本身、修改結(jié)果等)
    注:T代表抽象類型自身,t是其他類型,+表示類型出現(xiàn)一次或多次,*表示類型出現(xiàn)零次或多次。

例:

  • Integer.valueOf() – Creator
  • new ArrayList() – Creator
  • Arrays.asList() – Creator
  • String.concat() – Producer
  • BigInteger.mod() – Producer
  • String.toUpperCase() – Producer
  • List.size() – Observer
  • String.length() – Observer
  • Map.keySet() – Observer
  • List.addAll() – Mutator
  • BufferedReader.readline() – Mutator

設(shè)計抽象數(shù)據(jù)類型

規(guī)則:

  • 設(shè)計簡潔、一致的操作
  • 要足以支持客戶端的需要,且用操作滿足需要的難度要低
  • 選擇表示空間與抽象空間,并在代碼中寫明選擇及AF和RI
  • 表示泄露的安全聲明(safety from rep exposure)
  • 注:AF、RI應(yīng)在代碼中以注釋形式寫出,而不能在Javadoc文檔中,防止被外部看到而破壞表示獨立性/信息隱藏。

    后兩條規(guī)則具體示例:
    Chapter 6 課件 P82 ~ P84

    測試抽象數(shù)據(jù)類型

    • 測試creators, producers, and mutators:調(diào)用observers來觀察結(jié)果是否滿足規(guī)約
    • 測試observers:調(diào)用creators, producers, and mutators等方法產(chǎn)生或改變對象,來看結(jié)果是否正確

    風(fēng)險:如果被依賴的其他方法有錯誤,可能導(dǎo)致被測試方法的測試結(jié)果失效!

    表示獨立性

    client使用ADT時無需考慮其內(nèi)部如何實現(xiàn),ADT內(nèi)部表示的變化不應(yīng)影響外部規(guī)約和客戶端。

    違反表示獨立性的一個示例:

    違反原因:ADT修改后客戶端代碼受影響(無法再使用get方法)

    保持表示獨立性的一個示例:

    表示不變性

    表示不變性(represetation invariant, RI)可以看作:

    • 某個具體的“表示”是否是“合法的”
    • 所有表示值的一個子集,包含了所有合法的表示值
    • 一個條件,描述了什么是“合法”的表示值

    精確記錄RI——rep中所有fields何為有效

    使用checkrep()私有方法檢查RI:

    • 在所有可能改變表示的方法內(nèi)都要檢查
    • Observer方法不改變表示,但以防萬一建議也要檢查

    如何建立表示不變性:

    • 構(gòu)造器和生產(chǎn)器在創(chuàng)建對象時要確保不變量為true
    • 變值器和觀察器執(zhí)行時必須保持不變性
    • 每個方法返回前,用checkRep()檢查不變量是否保持

    用ADT不變量可取代復(fù)雜的前置條件,相當(dāng)于將復(fù)雜的前置條件封裝到了ADT內(nèi)部。

    抽象函數(shù)

    首先引入表示空間與抽象空間的概念:

    抽象空間(A空間):客戶端看到和使用的值
    表示空間(R空間):ADT對于數(shù)據(jù)的內(nèi)部表示
    ADT開發(fā)者要同時關(guān)注抽象空間和表示空間,客戶端只需關(guān)注抽象空間。

    表示空間 → 抽象空間的映射關(guān)系:

    • 抽象空間的每個值一定有表示空間的值與其對應(yīng)——滿射
    • 一些抽象空間的值可能有多個表示空間的值與之對應(yīng)——未必單射
    • 表示空間中某些值可能沒有對應(yīng)的抽象空間的值——未必雙射

    抽象函數(shù)(abstraction function, AF):表示空間和抽象空間之間映射關(guān)系的函數(shù),即如何去解釋表示空間中的每一個值為抽象空間中的每一個值。

    精準(zhǔn)記錄AF——如何解釋每一個表示空間的值(映射關(guān)系)

    表示不變性(RI)與抽象函數(shù)(AF)之間的關(guān)系

    • 不同的內(nèi)部表示,需要設(shè)計不同的AF和RI
    • 選擇某種特定的表示方式R,進(jìn)而指定某個子集是“合法”的(RI),并為該子集中的每個值做出“解釋”(AF)——即如何映射到抽象空間中的值
    • 即使是相同的R、RI,也可能有不同的AF,即“解釋不同”

    例:
    選擇字符串作為字符集合的表示方式,一種可能的對應(yīng)RI、AF如下:

    public class CharSet {private String s;// Rep invariant:// s.length() is even// s[0] <= s[1] <= ... <= s[s.length()-1]// Abstraction function:// AF(s) = union of {s[2i], ..., s[2i+1]} for 0 <= i < s.length()/2

    則有:

    • “ad”、“eeee”、"abcd"滿足RI,“adad”、"abc"不滿足RI
    • AF(“acfg”) = {a, b, c, f, g}
    • AF(“tv”) = AF(“ttuv”) = AF(“ttuuvv”)

    表示泄露

    “表示泄露”不僅影響表示不變性,也影響了表示獨立性。
    一旦發(fā)生,ADT內(nèi)部表示可能在程序任何位置發(fā)生改變(而不是限制在ADT內(nèi)部)。
    除非迫不得已,否則不要把希望寄托于客戶端上,ADT有責(zé)任保證自己的不變性,并避免“表示泄露”。
    最好的辦法就是使用immutable的類型,徹底避免表示泄露!

    表示泄露的安全聲明——給出理由,證明代碼并未對外泄露其內(nèi)部表示。

    有益的可變性

    對于不可變的抽象數(shù)據(jù)類型,它在抽象空間內(nèi)的抽象值應(yīng)是不變的,但其內(nèi)部表示的表示空間取值是可以變化的。

    :一個使用兩個int型變量來表示分?jǐn)?shù)(AF、RI略,表示的分?jǐn)?shù)為numerator / denominator)的ADT,其toString()方法可以修改其內(nèi)部表示(化簡分?jǐn)?shù)):

    /*** @return 分?jǐn)?shù)的可讀字符串表示*/ @override public String toString() {int g = gcd(numerator, denominator);/* 化簡分?jǐn)?shù),以便輸出人更易讀的值 */numerator /= g;denominator /= g;if (denominator < 0) {numerator = -numerator;denominator = -denominator;}checkRep();return (denominator > 1) ? (numerator + "/" + denominator): (numerator + ""); }

    注意: 這種mutation僅改變了表示空間的值,并未改變抽象空間的值,對于客戶端來說是利用了”AF未必單射“,從一個表示空間值變成了另一個表示空間值,但這并不代表不可變的類中可以隨意出現(xiàn)mutator方法!

    總結(jié)

    以上是生活随笔為你收集整理的哈工大软件构造课程知识点总结(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。