제이온

[物件] 第 2 章 物件導向程式設計

  • 撰写语言: 韓国語
  • 基准国家: 所有国家country-flag
  • 信息技术

撰写: 2024-04-28

撰写: 2024-04-28 13:46

電影預訂系統


需求檢視

  • 想要實作線上電影預訂系統。
  • 電影表示電影的基本資訊。
    • 例如片名、放映時間、價格資訊等。
  • 放映表示觀眾實際觀看電影的事件。
    • 例如放映日期、時間、場次等。
  • 人們說預訂電影,但實際上應該說預訂特定正在放映的電影才正確。
  • 折扣條件
    • 價格是否折扣。
    • 順序條件:利用放映場次決定是否折扣。
    • 期間條件:利用電影放映開始時間決定是否折扣。
  • 折扣政策
    • 決定折扣價格。
    • 金額折扣政策:預訂價格減去一定金額。
    • 比例折扣政策:原價減去一定比例的價格。
  • 每部電影可以分配一個折扣政策或不分配,折扣條件可以混合多個折扣條件。
  • 即使有套用折扣政策,但如果沒有滿足折扣條件,或沒有套用折扣政策,則不折扣價格。


邁向物件導向程式設計

合作、物件、類別

  • 物件導向就是以物件為導向。
    • 不應該在決定類別後才思考類別需要哪些屬性和方法。
    • 應該決定哪些物件具有哪些狀態和行為。
    • 不應該將物件視為獨立的存在,而應該視為合作社群的一份子。


遵循領域結構的程式結構

  • 領域是指使用者為了解決問題而使用程式的範圍。

<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe7d22a03-4a24-40e9-8068-bd03b9fd816b%2FUntitled.png?table=block&id=3f1931fc-8ef9-470a-8189-3727146638f6&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/438;" width="2000" height="438"></span>

  • 通常,類別的名稱應與對應的領域概念的名稱相同或至少相似。
  • 類別之間的關係也應盡可能與領域概念之間的關係相似,以便於理解和預期程式的結構。


實作類別

  • 類別分為內部和外部,為了設計出優秀的類別,必須決定哪些部分公開給外部,哪些部分隱藏。
    • 將物件的屬性設為 private 並封鎖,並公開需要變更內部狀態的方法。
  • 區分類別的內部和外部可以確保物件的自主性,從而為程式設計師提供實作的自由。


自主物件

  • 物件必須是具有狀態和行為的自主物件。
  • 將資料和功能一起封裝到物件內部稱為封裝。
  • 透過存取控制減少外部干擾,物件才能自行決定其行為。
  • 介面和實作分離原則是物件導向程式設計必須遵循的主要原則。
    • 公開介面:外部可存取的部分。
    • 實作:僅內部可存取的部分。


程式設計師的自由

  • 程式設計師的角色分為類別撰寫者和用戶端程式設計師。
    • 類別撰寫者新增新的資料型態。
    • 用戶端程式設計師使用類別撰寫者新增的資料型態。
  • 實作隱藏
    • 類別撰寫者可以只提供必要的資訊給用戶端程式設計師,並隱藏內部實作。
    • 用戶端程式設計師只需要知道介面,因此可以減少知識量。


合作物件的社群

  • 在表示金錢時,最好使用 Money 等物件包裝,而不是僅僅宣告 Long 型態的變數。使用物件可以更好地傳達含義,並且可以在一個地方執行重複的運算處理。
  • 為了實作系統的某個功能,物件之間的互動稱為合作。


關於合作的簡短故事

  • 物件與其他物件互動的唯一方式是傳送或接收訊息。
  • 處理接收到的訊息的方法稱為方法。
  • 區分訊息和方法很重要,多型性的概念由此開始。


計算折扣價格

開始進行計算折扣價格的合作

  • Movie 類別中沒有包含有關折扣政策的詳細邏輯,而是委託給 DiscountPolicy 介面。使用繼承、多型性和抽象化非常重要。


折扣政策和折扣條件

<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F7b9b27a5-0dac-4ba7-9552-05b7f8fbdecd%2FUntitled.png?table=block&id=3264f189-6e12-4a55-94d2-75b851320c7a&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/535;" width="2000" height="535"></span>


繼承和多型性

編譯時期相依性和執行時期相依性

  • 程式碼的相依性和執行時點的相依性可能不同。
  • 兩者之間的相依性差異越大,程式碼越難理解,但程式碼會更具彈性和可擴展性。


基於差異的程式設計

  • 繼承可以基於現有類別輕鬆快速地新增新類別,並重複使用父類別的實作。
  • 建立新類別的方法是只新增與父類別不同的部分,這種方法稱為基於差異的程式設計。


繼承和介面

  • 繼承會讓子類別繼承父類別提供的所有介面。
  • 介面定義物件可以理解的訊息清單。
  • Movie 向 DiscountPolicy 傳送 calculateDiscountAmount 訊息。對 Movie 而言,哪個類別的實例回應並不重要,只要成功回應即可。
  • 因此,AmountDiscountPolicy 和 PercentDiscountPolicy 都可以代替 DiscountPolicy 與 Movie 合作。
  • 像這樣子類別代替父類別稱為向上轉型。因為子類別看起來像是自動轉型為位於上層的父類別。


多型性

  • 多型性是指接收相同訊息時,根據物件的型別做出不同回應的能力。
    • Movie 傳送相同的訊息,但實際上執行哪個方法取決於接收訊息的物件的類別是什麼。
  • 多型性基於程式碼的編譯時期相依性和執行時期相依性可能不同的事實。
  • 多型性在執行時決定要執行哪個方法,因此稱為延遲繫結或動態繫結。


介面和多型性

  • 如果不需要共用實作,而只想共用介面,則可以使用介面而不是抽象類別。


抽象化和彈性

抽象化的力量

  • 抽象化的優點
    • 如果只單獨檢視抽象化的層級,就可以在較高層級描述需求的政策。
    • 設計變得更具彈性。


彈性設計

  • 抽象化可以防止設計與具體情況結合,因此可以建立彈性的設計。


抽象類別和介面的權衡取捨


  • 目前 NoneDiscountPolicy 事實上沒有問題,因為 DiscountPolicy 的 calculateDiscountAmount() 方法在沒有折扣條件時會傳回 0。但是,從使用者的角度來看,必須在 Movie 的參數中加入沒有折扣政策的 None 政策,因此新增了這個類別。
  • 因此,從概念上來說,NoneDiscountPolicy 類別容易造成混淆,如果修改成以下方式,會比較容易理解。



  • 如上所述,將 DiscountPolicy 抽象化為介面,並將其實作分為 NoneDiscountPolicy 和表示一般折扣政策的 DefaultDiscountPolicy。

<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F712983a9-3937-4265-82fe-66a144c44a0f%2FUntitled.png?table=block&id=f5ca651c-d03c-4a6c-97e9-7443ee5649a0&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/886;" width="2000" height="886"></span>

  • 有些人可能會認為,為了僅僅一個 NoneDiscountPolicy 而新增介面,相較於增加的複雜度,效率並不高。
  • 必須意識到與實作相關的所有內容都可能是權衡取捨的對象,並進行設計。也就是說,撰寫的所有程式碼都必須有其正當理由。


程式碼重複使用

  • 可以使用繼承重複使用程式碼。
  • 但是,為了重複使用程式碼,最好使用組合而不是繼承。
  • 在目前的程式碼中,Movie 重複使用 DiscountPolicy 程式碼的方式就是組合。
  • 如果將 Movie 作為上層類別,並分成 AmountDiscountMovie 和 PercentDiscountMovie,則表示使用繼承。


繼承

  • 繼承的缺點
    • 違反封裝。
      • 必須充分了解父類別的內部結構。
      • 修改父類別時,子類別也必須一併修改的可能性很高。
    • 使設計缺乏彈性。
      • 在編譯時期決定父類別和子類別的關係。
      • 無法在執行時期變更物件的種類。
      • 但是,組合可以在使用物件的一方透過 changeDiscountPolicy() 等方法在執行時期替換實例。


組合

  • 僅透過介面中定義的訊息重複使用程式碼的方法稱為組合。
  • 可以實作封裝,並維持鬆散耦合。
  • 為了達到多型性而重複使用介面的情況下,必須結合繼承和組合來使用。
    • 例如,DiscountPolicy 介面只能透過繼承來實作其子實作。


資料來源

  • 物件

评论0