# 物件導向 - 鄭永斌 ## 2. - 會按照繼承的順序依序執行父類的建構子,倒著執行解構子。每一個 subclass 要自行負責建構與清除自己特異化的部分 - member initialization list:`Rat(int w) : Pet(w){}`,執行指定的父類建構子 - overload 多載 != polymorphism 多型 - 如果 override 一個在父類 overloaded (名字一樣,參數不一樣)的 method,沒被 override 的其他同名 method 都會不見,無法被call。(因為編譯器要你確定全都有 override) - `(Pet) Cat.speak()`:轉型時,compiler會自動 call copy constructor,之後再 destruct 掉 ## 3. Polymorphism 用 base class 的指標來處理時,可以根據 subclass 做不同的處理 e.g. ```c for(Entity E in list) { E->draw(); } ``` 以下是說 c++ - 任何想被子類 override 的 method 都要宣告成 virtual,一旦被宣告成 virtual,在子類中都會是 virtual,但還是建議加一下比較好' - 多型只對 pointer、reference,以及宣告成 virtual 的函式有效 - 如果一個 class 有任何一個 method 是 virtual 的,destructor 也要是 virtual - 總之就是子類可能會自己特異化實現的用 virtual,但不要乾脆就全 virtual,因為有 overhead - **object slicing**:pass by value 的時候,如果參數型別是基類,那傳子類進去時,子類的記憶體會被切掉,只會copy出一個基類物件 - 以前 C 沒有 OO 的時候就要 hardcode switch 來做多型,或是用 function pointer 和 function array - **Indirect call**:間接呼叫,利用存在暫存器中的地址在執行時定址。e.g. `MOV [EBX], 123` - **binding**:把記憶體位址綁到 call function 的地方 - ++compilation time binding++:自己寫的函式 - ++linking time binding++:C 內建的函式 - ++loading time binding++:去外界參考表找 function 的位址,而位址要等OS把DLL(dynamic linking library)載入到記憶體後再填進去 ![image](https://hackmd.io/_uploads/S1jh5Vk21l.png) - Dynamic Binding:維護並使用 Virtual Function Table,一個 class 只會有一個,各實例共用 ![image](https://hackmd.io/_uploads/SJiKfS1nJl.png) - abstract class:有純虛函式 pure virtual function `virtual void myFunc() = 0;`,因此不可能有這 class 的實例 ## 4. Multiple Inheritance - **Percolating Upward**:為了多型,把子類特異化的部分移到父類 - `dynamic_cast<[TYPE]> [VAR]`:試著把 `VAR` 轉成 `[TYPE]` 並回傳,不行就回傳 `NULL` - casting up / down:轉成 父/子 類 - Percolating Upward 跟 Casting Down 都是 bad design,因為無法做到 ++跟未來擴充型別無關++,無法應付未來的擴充,需要回去改 code - 多重繼承:子類繼承自兩個父類,兩個父類又繼承自同一個祖父類,則子類會 call 兩次祖父類的 constructor,並且會有兩個祖父類的記憶體空間 ![image](https://hackmd.io/_uploads/B1GolCfhkl.png) ### c++ - 因為這樣重複的記憶體會有 ambiguity,所以 C++ 有提供一些解法 - 指定:`jetCar->Jet::stop()`,甚至是 `jetCar->Jet::Vehicle::run()` - 子類 override 掉 - 但就算這樣有時還是不對,比如說祖父類的 "資料" 會有兩份 - **Diamond-shaped Inheritance**:鑽石型繼承,父類在繼承祖父類時使用 `virtual` 關鍵字,在多重繼承時就只會有一個祖父類 ### java - **Interface**:就是一個只能宣告純虛函式的 class,要繼承的話要用關鍵字 `implement`,然後子類自己填定義 - 介面的使用原則:A implement B,表示 A **can do** B ## 5. Comparison of Java and C++ - Java 如果要呼叫父類的建構子要用 `super()` 而且這只能在子類建構子的第一行 call,也不能用任何的 `this.xxx` 來當參數 - `super.func()`:可用來 call 父類被覆寫的函式 - `myClass[100]`:C++ 會建立 100 個物件呼叫 100 次建構子;Java 不會,只會建立 reference,所以不會 call 建構子,要之後自己 new 物件 - Java 的 primitive type 都是 pass by value;class type 都是 pass by reference - Java 沒有 global variable ## 6. Code Quality 沒什麼特別的 ## 7. DataBase Design and Normalization - Normalization:只讓資料庫包含恰恰能描述的資料 - 移除重複的冗餘資料 (去除重複的column) - 確保關連性合理 - foriegn key:連到另一個 table 的 column - **1st Normal Form** ![image](https://hackmd.io/_uploads/rJj2Zobakg.png =40%x) ![image](https://hackmd.io/_uploads/r1VJfjZ6Je.png =40%x) - **2nd Normal Form** 移除跟 primary key 無關聯的 column ![image](https://hackmd.io/_uploads/H1cwQiW61x.png =60%x) - **3rd Normal Form** Non-key value 不能有相關性 ![image](https://hackmd.io/_uploads/S1DAUoZ6Jg.png) ## 8. Data-Oriented Model - middle-level notation:把設計系統時的心路歷程記下來,希望可以把高手的作法歸結出一個能照著做的方法論 - **ERD**:Entity-Relation Diagram,專注在data間如何link跟組織 - The Entity Relationship **Principle**:list of ***things*** - Entity type = class = 一個 table - Entity = object - Occurrence = instance - Attribute = 一個欄位 - Assotioation: 動作 = 一個 Access path way (i.e. foreign key) - 各種 programming language 的發明都是為了解決 software engineering 的問題 - 物件導向的程式就是為了避免之後要一直改 - Multiplicity:多對一、一對多、many-to-many ## 9. How to find classes and objects - **Jacobson's Three Types** - **Entity objects**:things in the users' real world - ++concrete objects++:Employee, Product, Tool, etc - ++Conceptual objects++:Corporation, strategy, membership, approval, etc - ++Event and State objects++:Purchase, delivery, arrival, ownership, status, etc - **Interface objects**:comminucation protocol,GUI、真實世界的SOP、既有系統的interface, etc - **Control objects**:To carry complex methods that don't have a class they obviously belong in - **The KRB Seven-Step Method** 1. ++Candidate Classes++:列出跟你的project有關的所有名詞(name),也許能當class 2. ++Define Classes++:決定要有哪些class,每個候選的class都需要經過下列三個檢查 1. A Real-World Identifier:"How do I tell one ... from another?" 這class的物件彼此間能不能區分(每位學生都不同) 2. A Definition:"What is a ... ?",能不能用一句話給這物件一個定義 3. Sample Attributes and Behaviors 3. ++Establish Associations++:物件的互動 ![image](https://hackmd.io/_uploads/Hk6oDcLyxg.png =60%x) 4. ++Expand Many-to-Many Associations++:新增class去解掉M:M的情況 ![image](https://hackmd.io/_uploads/ByV0dqLylx.png =48%x) ![image](https://hackmd.io/_uploads/S1E7tq8Jle.png =45%x) 5. ++Attributes++:列出每個物件需要有的屬性 6. ++Normalization++:正規化,database的事情 7. ++Operations++:Behavior,物件的method 8. 根據物件的相似性建構繼承關係 ## 10. Overview of UML 物件導向除了可重用、好維護外,還有一個重要的點是可以 modeling software before building it - UML:Unified Modeling Language ## 12. UML class diagram - composit:sub class 擁有 base class 型別的物件 ### Class Diagram - 描述系統中物件的 class,以及 class 間的**靜態**關聯 - Assotiation:class 間的連線箭頭表示,擁有者指向被擁有者,但 UML 2.x 移除的,不用箭頭 - Generalization 空心箭頭,表示繼承自 ![image](https://hackmd.io/_uploads/Sk8pHn_xxx.png =70%x) ### Object Diagram 又被稱作 instance diagram,是系統的快照 ![image](https://hackmd.io/_uploads/HJSyLhulxg.png =70%x) method 畫底線是 class scope (static) 的 ![image](https://hackmd.io/_uploads/SkPzIndelx.png =70%x) ### Multiple Classification 連接線上的 Discriminator 解釋特異化的意義 (實心箭頭表示不能再被繼承下去) ![image](https://hackmd.io/_uploads/S1suLnuxgx.png =70%x) ### Dynamic Classification 標一個 \<<dynamic\>> 表示型別可能會互相轉換 ![image](https://hackmd.io/_uploads/S1qaw2Olee.png =70%x) ### Aggregation and Composition association 的一種 - Aggregation:聚集,一個沒了另一個還能存在。空白菱形 - Composition:合成,不可分割,同生同滅。實心菱形 菱形都是指向大的那邊 ![image](https://hackmd.io/_uploads/Byfyc2_xge.png =70%x) ### Derived Association and Attribute 衍生的關聯或屬性,用 `/` 標註,實作時不須用一個欄位紀錄,從其他關連或屬性去推就好,比如說有++生日++就不用記++歲數++ ![image](https://hackmd.io/_uploads/rygdj2ulgg.png =70%x) ### Interface and Abstract Class 用虛線 - Abstract ![image](https://hackmd.io/_uploads/SJHn23_gxe.png =70%x) - Interface ![image](https://hackmd.io/_uploads/rylwA3Oele.png =70%x ) ### Classification and Generalization 1. 小白是狗 2. 狗是物種 但小白不是物種 雖然他們口語都是 is-a 關係,但 Generalization (繼承)有遞移性 classification 沒有遞移性 ### Qualified Association 三小 ![image](https://hackmd.io/_uploads/Hy1BW6uxlg.png =70%x) ### Association Class 給連線一個 class ![image](https://hackmd.io/_uploads/SyZSM6ulxg.png =70%x) 其實就是省略一些中間 class,上圖等價下圖 ![image](https://hackmd.io/_uploads/H1y7zadxle.png =70%x) ### Template Class C++ 的 template,標在右上角 ![image](https://hackmd.io/_uploads/B1tW7Tuglg.png =70%x) ![image](https://hackmd.io/_uploads/SJmEQauxle.png =70%x) ### 箭頭 knows a 是只有指標,has a 是創建跟刪除物件 ![image](https://hackmd.io/_uploads/H1ITMQFlxe.png) ## 13 UML sequence diagram - 又叫 interaction diagram,描述 objects (不是class) 間如何合作完成一件事 - sequence diagram - collaboration diagram ### sequence diagram - 由上到下表時間順序 - `*` 表示有 for loop ![image](https://hackmd.io/_uploads/r1zxB3Klxe.png =70%x) - 半個箭頭表示 asynchronous ![image](https://hackmd.io/_uploads/r1GVI3Yell.png) - sequence diagram 不擅長展示有loop等的演算法,適合用來展示複雜的互動環境 ![image](https://hackmd.io/_uploads/Hy0CwnKglg.png =70%x) (中間小圈O->是傳參數) ![image](https://hackmd.io/_uploads/r1pm_2Fxle.png =70%x) ### collaboration diagram - 因為 sequence diagram 很容易太長,所以 collaboration diagram 改用數字標執行順序,不寫成一條了。 ![image](https://hackmd.io/_uploads/SkNEthtxll.png =70%x) ### How to find methods of object - two method - **Maximize**:如果是要寫 library,設計物件的時候不知道別人會怎麼用,那就多寫一點method - **Minimize**:如果是自己要完成一個軟體。那就不要寫不會用到的 method ## 11. Movie rental Example - 一個設計是否良善要看未來維護需求是甚麼 - software entropy:愈來愈亂 ### State Pattern 將一個物件的多種狀態封裝在不同的類別中,從而使狀態轉換更為靈活和可維護 跟 Strategy Pattern 看起來很像,但一個是狀態轉移,一個是行為更換。State Pattern 的行為邏輯沒有被抽出來,Strategy的有。 ## 14. Design Pattern 1 有本四人幫(The gang of Four)的書能看 - **Design Pattern**:過去在實作各種各類的軟體過程中,許多人累積了寶貴的物件導向分析經驗。經過蒐集整理,這些寶貴的繼承架構,class diagram,物件互動架構等等,被蒐集成所謂的design patterns - **KISS**:Keep It Simple and Stupid ### Composite Pattern - 如果物件用composite 包含 base class,那就不要把特異化放在 sub class 了,直接 percolating up 放到 base class,不然還要判斷當前物件是甚麼類型才能 call 特異化的部分 ![image](https://hackmd.io/_uploads/rkB1XBsWxx.png) ### Proxy Pattern ### Singleton Pattern - Global Variable is EVIL:不知道誰能存取它、耦合、汙染命名空間、多執行緒會有 concurrency 的問題 - Singleton:建構子是 private,物件等需要(第一次get)才建立,確保 class 只有一個 instance ### Strategy Pattern - composition 可能比繼承好 - 假設有各種鴨子,++綠頭鴨++、++橡皮鴨++、++木雕鴨++,如果都繼承自「鴨子」,而鴨子有++叫++、++飛++等 function,那++橡皮鴨++、++木雕鴨++都需要各自override它們為空,導致代碼重用性很差。唉,總之就是物件裡面的方法再拉出來寫成另一個物件(比如說這些行為物件可能是實現一個叫做 behavior 的 interface 之類的)這樣就可以在物件間 reuse,甚至還能在 runtime 抽換掉 (如果用繼承來搞不同物件的行為的話,就沒法在 runtime 轉成另一個 sub class 了) ![image](https://hackmd.io/_uploads/HkQv-IsZgl.png) ## 15. Design Pattern 2 ### Factory Pattern > [!Note] Design Principle > **Close for Modifications**:要改code的時候不用到處改,那就要把核心 code 都用 interface 跟多型(Program to an interface, not an implementation) > > **Dependency Inversion Principle**:高層類別不該依賴於底層類別,要搞抽象就全都抽象 把 `new Subtype1()` 這類創建物件的東東移到 factory 物件裡,要創建物件的時候,傳參數(string 或 enum 之類的)進去 Factory 的 `createObject(Type)`,總之就是把 `new Subtype1()` 抽出來,這樣以後要改或擴充的話,去 factory 改就好 並且如果 subtype 有再分化下去成 subsubtype 的話,factory也搞個繼承變 subFactory,`createObject(Type)` 也弄成 abstract 搞多型,天知道為啥這樣比較好 ![image](https://hackmd.io/_uploads/S1GpUDibex.png =70%x) ![image](https://hackmd.io/_uploads/BkNnBPsZgl.png =70%x) ![image](https://hackmd.io/_uploads/HJyje_j-eg.png =30%x) $\Rightarrow$ ![image](https://hackmd.io/_uploads/ryY2x_iWgl.png =30%x) 或是再把 Factory 也從使用它的 class 中抽出來,改在建構時傳進去,更解耦合 ![image](https://hackmd.io/_uploads/BJMvRvjbgg.png =50%x) ### Decorator Pattern > [!Note] Design Principle > Classes should be open for extension, but closed for modification 用有點像 composition 那樣的方式,從基底 class 一層一層包 decorator 上去,達到類似繼承的差異化 ![image](https://hackmd.io/_uploads/B1W8aFj-eg.png =80%x) 舉例來說,有不同的咖啡,以及不同的配料,要計算價錢,那就基底看要哪種咖啡,然後一層一層加不同配料上去,每個 decorator 和基底 class 都有 `getCost()` function,要用的時候從最外面一層層 call 進去 ![image](https://hackmd.io/_uploads/BkHZwFi-gx.png =60%x) ![image](https://hackmd.io/_uploads/H17naYo-ge.png =80%x) ![image](https://hackmd.io/_uploads/B15CTts-gl.png =70%x) ### Model View Control > GUI 是軟體中最常面對變動的東東 - Model:the computational model - View:負責把 data 畫出來 - Controller:負責 user event,然後跟 model 互動(本身不該有運算邏輯的部分,只負責怎麼把資料給 View) ![image](https://hackmd.io/_uploads/ByOfam2Zgg.png =80%x) #### Observer Pattern Observer Pattern 定義了一種一對多的依賴關係,讓一個或多個觀察者物件監聽其所關心的主題物件。當這個主題物件發生狀態改變時,會對所有的觀察者發送通知。 ![image](https://hackmd.io/_uploads/B1fvgN2beg.png =70%x)