天天看點

軟體構造複習筆記(3)

注:文章中帶有 * 的标題表示往年考試中出現過相應考點

文章目錄

    • 第七章 面向對象的程式設計(OOP)
      • 1 基本概念:對象、類、屬性、方法*
      • 2 接口和枚舉*
      • 4 封裝和資訊隐藏*
      • 5 繼承和重寫*
        • Overriding*
        • 抽象類
      • 6 多态、子類型、重載*
      • 9 動态分派
      • 10 一些Java中的重要對象方法*
      • 11 設計好的類*
      • 12 OOP曆史
    • 第八章 ADT和OOP中的“等價性”
      • 1 等價關系*
      • 2 不可變類型的等價性
      • 3 == 和 equal()*
      • 4 實作equal()
      • 5 對象契約*
      • 6 可變類型的等價性
      • 7 自動封裝和等價性
    • 第九章 面向複用的軟體構造技術
      • 1 什麼是軟體複用
      • 2 如何度量可複用性
      • 3 可重用部件的等級和形态
      • 5 設計可複用類*
        • Liskov替代原則(LSP)*
        • 委派群組成*
      • 6 設計系統級可複用API庫和架構

第七章 面向對象的程式設計(OOP)

1 基本概念:對象、類、屬性、方法*

對象:是狀态和行為的組合

狀态 - 對象中所包含的資料 - 類中的執行個體變量

行為 - 對象所支援的行為 - 類中的執行個體方法

類:每個對象都屬于某個類,方法定義了類型和實作

類成員變量:一個和類相關而非類的執行個體相關的變量 - 靜态成員變量

類方法:之和類相關的方法 - 靜态方法

注:本節為基礎知識,需要掌握

2 接口和枚舉*

接口(Interface):一個方法聲明的清單,不包含方法體,可以由類實作

接口間可以繼承和擴充

一個類可以實作多個接口(進而具備了多個接口中的方法)

一個接口可以有多種實作類

軟體構造複習筆記(3)

接口 - 确定ADT規範,類 - 實作ADT

可以不需要接口直接使用類作為ADT,既有ADT定義也有ADT實作

但實際中更傾向于使用接口來定義變量

打破了抽象邊界,接口定義中沒有包含constructor,也無法保證所有實作類中都包含了同樣名字的constructor。

故而,用戶端需要知道該接口的某個具體實作類的名字。可以提供靜态工廠方法而非構造函數來向用戶端提供具體實作類。

接口中每個方法都需要在所有實作它的類中實作

可以通過default關鍵字修飾方法,在接口中統一實作某些功能,無需在各個類中重複實作它

以增量式的為接口增加額外的功能而不破壞已實作的類

枚舉:

軟體構造複習筆記(3)
軟體構造複習筆記(3)

注:本節了解一下接口就行了

4 封裝和資訊隐藏*

資訊隐藏:區分子產品設計好壞的唯一最重要的因素是它對其他子產品隐藏内部資料和其他實作細節的程度,設計良好的代碼應該能隐藏全部實作細節

通過接口進行資訊隐藏:

1.使用接口類型聲明變量

2.用戶端僅使用接口中定義的方法

3.用戶端代碼無法直接通路屬性

權限修飾符:

private:隻能在類内部進行使用

protected:可以在其子類及同個包中的其他類中使用

public:在所有類中都可以使用

資訊隐藏政策:

1.認真設計API

2.隻提供用戶端需要的功能,其他所有成員都應該是private的

3.你可以在不破壞用戶端的情況下将任何一個private成員修飾為public

注:本節需要了解權限修飾符的功能

5 繼承和重寫*

Overriding*

可重寫的方法:未加final修飾的方法都可以在子類中重寫,即在子類中将該方法重寫實作,重寫的方法有着和原方法完全相同的聲明,實際執行時調用哪個方法,在運作時決定

嚴格繼承:子類隻能添加新的方法,無法重寫超類中的方法

如果一個方法不能被重寫,那它一定以final修飾

通産override的方法都需要在方法聲明前添加@override

final作用:

1.變量 - 使變量在初始化後不能再改變取值

2.方法 - 避免子類中重寫該方法

3.類 - 避免該類被繼承

重寫時,可以使用super()複用父類中函數的功能,并在後續代碼中進行拓展

重寫時,不要改變原方法的本意

抽象類

抽象方法:存在有聲明,但沒有實作的方法,這個方法由abstract關鍵字修飾

抽象類:存在至少一個抽象方法的類,該類必須由abstract關鍵字修飾,抽象類不能被執行個體化

接口可以被認為是隻有抽象方法的抽象類

如果某些操作是所有子類型都共有,但彼此有差别,可以在父類型中設計抽象方法,在各子類型中重寫。

所有子類型完全相同的操作,放在父類型中實作,子類型中無需重寫。

有些子類型有而其他子類型無的操作,不要在父類型中定義和實作,而應在特定子類型中實作。

注:繼承、重寫是重要概念,必須掌握

6 多态、子類型、重載*

三種多态類型:

特殊多态 - 函數重載

參數化多态 - 泛型

子類型多态、包含多态 - 多個子類繼承某父類

重載(Overload):多個方法具有同樣的名字,但有不同的參數清單或傳回值類型

價值:友善用戶端使用,用戶端可用不同的參數清單,調用同樣的函數

重載時一種靜态多态:進行靜态類型檢查,根據參數清單進行最佳比對,在編譯階段時決定要具體執行哪個方法

重載規則:

1.必須有不同的參數清單

2.可以有相同/不同的傳回值類型

3.可以有相同/不同的權限修飾符

4.可以有新的或更廣泛的檢查異常

5.可以在同一個類内重載,也可以在子類中重載

軟體構造複習筆記(3)

重寫(Override)則是在運作時進行動态檢查,根據記憶體中對象的具體類型來調用對應方法

軟體構造複習筆記(3)

泛型:以泛型方式定義函數和類型,以便基于運作時傳遞的參數工作,即允許靜态類型化而不完全指定類型。

泛型程式設計:是一種程式設計風格,其中資料類型和函數用稍後指定的類型編寫,然後在需要時對作為參數提供的特定類型進行執行個體化。

類型變量:未指定的變量類型

泛型類:類定義中包含了類型變量

泛型接口:接口定義中包含了類型變量

泛型方法:方法定義中包含了類型變量

泛型的其他性質:

軟體構造複習筆記(3)

子類型:若B是A的子類型,意味着每一個B類型的變量都可以被當作A類型

B是A的子類型當且僅當B的Spec至少和A一樣強,子類型的規約不能弱化父類型的規約

子類型多态:不同類型的對象可以統一的處理而無需區分

注:重載、重寫應該掌握,泛型應該了解一下,子類型多态需要注意對子類型spec的要求

9 動态分派

動态分派:确定要在運作時調用的方法,即在運作時解析對已覆寫或多态方法的調用

靜态分派:重載的方法使用靜态綁定綁定,而重載的方法在運作時使用動态綁定綁定。

軟體構造複習筆記(3)

10 一些Java中的重要對象方法*

equals方法:當兩個對象等價時傳回true,應滿足對稱、自反、傳遞的性質

hashCode方法:傳回在哈希映射中使用的哈希代碼

toString方法:傳回一個可列印的字元串表示

軟體構造複習筆記(3)

注:應重點關注equal方法

11 設計好的類*

不可變類的優點:簡單、固有線程安全、可以自由共享、不需要防禦拷貝、優秀的建構塊

如何寫不可變類:

1.不提供任何mutator

2.確定方法都不會被重寫

3.使所有變量均被final修飾

4.使所有變量均被private修飾

5.確定任何可變類型的組成部分的安全性(避免表示洩露)

6.實作toString()、hashCode()、equals()等方法

注:需要學會怎麼設計不可變的類

12 OOP曆史

軟體構造複習筆記(3)
軟體構造複習筆記(3)

第八章 ADT和OOP中的“等價性”

1 等價關系*

ADT是對資料的抽象,展現為一組對資料的操作

抽象函數AF:内部表示->抽象表示

基于抽象函數AF定義ADT的等價操作

等價關系:自反、對稱、傳遞

軟體構造複習筆記(3)

注:需要了解什麼是等價關系

2 不可變類型的等價性

如果AF映射到相同的結果,則等價

站在外部觀察者的角度,對兩個對象調用任何相同的操作,都會得到相同的結果,則認為兩個對象是等價的,反之亦然

3 == 和 equal()*

== 運算符比較的是對象的引用,兩個對象指向同一個記憶體空間時,則說明這兩個對象具有引用等價性

equal()方法比較的是對象的内容,即對象等價性

在自定義ADT時,需要重寫Object的equals()

== 通常用于對基本資料類型判斷是否相等,equal()用于判斷對象類型是否等價

注:需要了解如何區分兩者差別

4 實作equal()

在Object中預設equals()是在判斷引用等價性,是以一般需要重寫

equal方法如果接受的參數不是Object類型則實作不是override而是overload

instanceof運算符可以判斷某一變量所指向記憶體是否屬于某各類型(動态檢查)

5 對象契約*

equal方法滿足的契約:

1.等價關系:自反、對稱、傳遞

2.除非對象被修改了,否則調用多次equals應有同樣的結果

3.對于非null引用x,x.equals(null)應傳回false

4.等價的對象,其hashCode()的結果必須相同

哈希表:

軟體構造複習筆記(3)
軟體構造複習筆記(3)
軟體構造複習筆記(3)

等價的對象必須有相同的hashCode,但不等價的對象也可以有相同的hashCode,不夠性能會變差

重載hashCode():

軟體構造複習筆記(3)

注:主要關注equals()方法

6 可變類型的等價性

觀察等價性:在不改變狀态的情況下,兩個mutable對象是否看起來一緻

行為等價性:調用對象的任何方法都展示出一緻的結果,可以認為就是引用等價性

對可變類型來說,往往傾向于實作嚴格的觀察等價性,但有時候觀察等價性可能導緻bug,甚至可能破壞RI

在hashSet等類型中,其内部的可變資料類型發生改變時,hashCode會改變,導緻hashSet的contains方法會判斷集合中改變過的内容不屬于集合

軟體構造複習筆記(3)
軟體構造複習筆記(3)

7 自動封裝和等價性

軟體構造複習筆記(3)

第九章 面向複用的軟體構造技術

1 什麼是軟體複用

軟體複用是使用現有軟體元件實作或更新軟體系統的過程

軟體複用的兩個視角:

1.面向複用程式設計(Creation):開發出可複用的軟體

2.基于複用程式設計(Use):利用已有的可複用軟體搭建應用系統

軟體構造複習筆記(3)

複用好處:

1.降低成本和開發時間

2.經過充分測試,可靠、穩定

3.标準化,在不同應用中保持一緻

2 如何度量可複用性

從以下幾個角度度量:

1.複用的機會有多頻繁?複用的場合有多少?

2.複用的代價有多大?

軟體構造複習筆記(3)

3 可重用部件的等級和形态

最主要的複用是在代碼層面,但軟體構造過程中的任何實體都可能被複用 - 需求、設計/規約、資料、測試用例、文檔

軟體構造複習筆記(3)

白盒複用:源代碼可見,可修改和拓展 - 複制已有代碼到正在開發的系統,進行修改

優點:可定制化程度高

缺點:對其修改增加了軟體的複雜度,且需要對其内部充分的了解

黑盒複用:源代碼不可見,不能修改 - 隻能通過API接口來使用,無法修改代碼

優點:簡單、清晰

缺點:适應性差些

複用一個類的方法:

1.繼承:子類可以對父類中的屬性、方法等進行複用

2.委派:在一個類中使用其他類的方法來實作自己的功能

架構:一組具體類、抽象類、及其之間的連接配接關系

開發者根據framework的規約,填充自己的代碼進去,形成完整系統

白盒架構:通過代碼層面的繼承進行架構拓展

黑盒架構:通過實作特定接口/delegation進行架構拓展

5 設計可複用類*

Liskov替代原則(LSP)*

子類型多态:用戶端可用統一的方式處理不同類型的對象

軟體構造複習筆記(3)

在Java中的編譯器強制執行的規則:

1.子類型可以增加方法,但不可以删

2.子類型中需要實作抽象類型中的所有未實作方法

3.子類型中重寫的方法必須傳回相同的類型或其子類型(滿足協變)

4.子類型中重寫的方法必須接收相同的參數類型(滿足逆變)

5.子類型中重寫的方法不能抛出額外的異常

LSP原則:子類方法必須相比于父類方法有着相同或更強的不變量,相同或更弱的前置條件,相同或更強的後置條件,才能使子類無條件地可以替代父類。

軟體構造複習筆記(3)
軟體構造複習筆記(3)

LSP是子類型關系的一個特殊定義,稱為(強)行為子類型

LSP依賴于以下限制:

1.前置條件不能強化

2.後置條件不能弱化

3.不變量要保持

4.子類型方法參數:逆變

5.子類型方法傳回值:協變

6.異常類型:協變

協變:随着父類型到子類型越來越具體,對于傳回值類型而言,不變或變得更具體,異常的類型也是如此

逆變:随着父類型到子類型越來越具體,參數類型會相反地變化,要不變或者越來越抽象

(目前Java中這種情況會被視作overload)

數組是協變的:根據Java的子類型規則,一個類型T的數組可以容納類型T和其子類型的變量

泛型不是協變的,ArrayList是List的子類型,但List不是類型List的泛型

泛型中的通配符:

軟體構造複習筆記(3)
軟體構造複習筆記(3)

委派群組成*

以排序為例,如果你的ADT需要比較大小,或者要放入Collections或Array進行排序,可實作Comparator接口建構比較器并override compare方法或者實作Comparable接口拓展ADT并override compareTo方法(不需要建構新的Comparator類,比較代碼防止ADT内部)

上述例子中,Comparator屬于delegation,而Comparable不屬于delegation

委派:一個對象請求另一個對象的功能,委派是代碼複用的一種常見形式

顯式委派:将發送對象傳遞給接收對象

隐式委派:通過成員查找規則

軟體構造複習筆記(3)

委派模式:通過運動時動态綁定,實作對其他類中代碼的動态複用

委派和繼承:

繼承通過拓展基類來添加新操作或重寫某操作

委派通過捕捉某個行為,并将其發送給另一個對象

很多設計模式都使用兩者組合

如果子類隻需要複用父類中的一小部分方法,則可以不需要使用繼承,而是通過委派機制來實作

一個類不需要繼承另一個類的全部方法時,可以通過委派機制調用部分方法,進而避免大量無用方法

軟體構造複習筆記(3)

委托發生在object層面,而繼承發生在class層面

組合複用原則(CRP):類應該通過其組合(通過包含實作所需功能的其他類的執行個體)來實作代碼重用,而不是從基類或父類繼承來實作多态行為和代碼重用。

軟體構造複習筆記(3)

CRP原則的思路:

1.使用接口定義系統必須對外展示的不同側面的行為

2.接口之間通過extends實作行為的擴充(接口組合)

3.類implements 組合接口,進而規避了複雜的繼承關系

軟體構造複習筆記(3)

delegation的類型:

1.Dependency:臨時性的delegation(作為方法的參數使用)

Dependency:對象需要其他對象(供應者)才能實作的臨時關系

2.Assosiation:永久性的delegation(作為對象的屬性使用)

Assosiation:對象類之間的持久關系,允許一個對象執行個體代表另一個對象執行個體執行操作。

3.Composition:更強的assosiation,但難以變化(屬性通過内部各方法進行初始化、修改等)

Composition:是一種将簡單的對象或資料類型組合成更複雜的資料類型的方法

4.Aggregation:更弱的assosiation,可動态變化(屬性通過外部方法進行修改)

Aggregation:對象存在于另一個外部,在外部建立,是以它作為參數傳遞給解釋器。

這四種類型都支援一對多的delegation

軟體構造複習筆記(3)

注:本節為重點,需要了解LSP、CRP、繼承、委派等概念的含義,并會分析及寫相應代碼

6 設計系統級可複用API庫和架構

庫:提供可複用功能的類和方法的集合

軟體構造複習筆記(3)
軟體構造複習筆記(3)
軟體構造複習筆記(3)

繼續閱讀