筆記 - 物件導向程式設計(Object-oriented programming) - ver1-part1
和ChatGPT討論並生成草稿,再透過自己的理解修改。
作為學習紀錄的用途。
參考Object-oriented programming - Wikipedia以及關聯頁面。
前言
程式的目的是為了解決需求(解決甚麼問題、如何解決問題),需求可以透過一系列的功能被滿足。
然而,僅以功能的設計,會遇到「Context(語意上下文或是情境)」(包含場景資訊、環境資訊)的管理問題。
例如: 要啟動空調,使用遙控器功能是: 運轉 ⇨ 調整溫度 ⇨ 調整風向。可以將這3個功能分成3個可以運作的遙控器,但是有共通的資料像是'空調模式',就會有同步資料問題。
而有多組功能時,這種方式的缺點的影響會更大。
從「語意上下文」的觀點出發,使用物件導向程式設計(Object-oriented programming)能夠處理這種問題。
透過「語意」將相關的功能和上下文資料封裝在一個物件內,讓每個物件具有明確的職責,使功能更符合「語意」。
概述
🎯 比喻
手邊有支筆,筆是物件(Object)。
'使用藍色原子筆作筆記'是「動作(方法)」,原子筆剩多少墨水是「狀態(資料)」,而'藍色墨水、原子筆、能夠作筆記'的筆,這樣的一組明確的規範,是類別(Class)。
📘 說明
- 現實的「事物」是物件(Object),具有「生命週期」。
- 以「需求(解決甚麼問題、如何解決問題)」擷取出「事物」的特性,將這組相關的特性也就是規範,組成類別(Class),沒有「生命週期」。
- 物件導向程式設計(Object-oriented programming)是一種以物件(Object)為核心來設計程式的方式,是一種強調模擬、抽象、模組化的思維。
- 類別(Class)包含了「狀態(資料)」與「行為邏輯(方法)」,它將「資料」與「方法」整合成一塊,描述角色、行為和互動、語意上下文。
- 使用類別(Class)建立具有生命週期的物件(Object)。
- 可以透過許多的規範,組成可管理的複雜系統,例如'科學計算機'。
- 這種方法可以套用在程式設計上,對於需求進行規劃和分析,設計成關聯的行為、明確的職責和角色、最小邊界的元素。
模型思維
- 將需求轉化為解決問題的「結構化模型」。
- 通常以「語意(業務語意)」為核心,並且各種「參與人員」對於「語意」有一致的定義。
- 有時一個簡單的語意可以分拆成多個互相協作的模組,並且每個模組包含多個互相協作的類別,例如'行事曆','使用者','保護的方式'。
- 適用於多種建構模型方式。例如分析、設計、實作,多個輪次的滾動式調整,並以建立最小功能系統為優先;例如分而治之,將大問題分成可組合的小問題,並將小問題一一實作。
模擬實物
🎯 比喻
汽車模擬器不需要實作完整的車,而是使用模擬。按鈕啟動引擎,方向盤控制車輪方向,油門影響引擎動力。模組相互運作就提供了現實汽車表現的特性。
📘 說明
- 透過類別(Class)定義模型,模擬出現實的實物的特徵和行為。
- 有的實物偏向資料,例如'表單文件(Form)';有的實物偏向方法,例如'工具(Tool)'。
模擬概念
🎯 比喻
公司裡面有會計師、業務專員、工程師等角色,每個角色都有必要的職責及相關的特性。
在「情境」之中,會表現出「一部分的特性」。
📘 說明
- 使用模型,來描述在一個系統內的單元與角色,這個系統可以有多種「場景」。
- 類別(Class)對應到概念的角色及其行為。
- 概念通常不是完整的系統,而是核心模組的一部分。
結構化、模組化、可維護性、重用性
🎯 比喻
使用多塊積木進行組合,而不是用整塊積木製作,是因為積木可以組裝、拆解與替換,更易維修與重構。
📘 說明
- 將大型系統拆解成小型模組,並能重複使用這些模組於不同場景中。這讓維護、除錯、測試與擴充更有效率。
1. 定義與特性
1. 類別(Class)與物件(Object)
- 類別(Class): 物件(Object)的模板,定義「資料(狀態)」與「方法(行為邏輯)」,是一種類型(Type)。
- 物件(Object): 類別(Class)的實例(Instance),具有「生命週期」和個別「狀態」。
- 🎯 比喻: 食譜描述'準備150ml的水',這裡的水是類別(Class);實際操作時,使用的水是物件(Object),其狀態可能是礦物質較多(偏鹼性)。
2. 介面(Interface)與抽象類別(Abstract Class)
-
介面(Interface): 一種完全抽象的類型(Type),一般不包含實作。它只定義「公開的(public)方法的合約(名稱、輸入資料、輸出資料)」與「公開的(public)屬性(名稱、資料)」。類別(Class)必須實作這些定義,才能「宣稱實作(具有)」該介面(Interface)。介面(Interface)強調「能力」與「角色」,而不是「資料(狀態)」。
- 🎯 比喻: 挑選電腦時,會考慮每種插槽可以如何使用,例如充電、連接手機。有的插槽都可以連接手機,有的插槽可以充電。一種插槽可以有多種功能,有充電功能,有連接手機功能,提供的「功能」就是介面(Interface)。
-
抽象類別(Abstract Class): 抽象類別(Abstract Class)主要作為其他類別(Class)的共同基底,定義一組共同介面與預設邏輯。它可以包含「抽象方法(無實作)」與「具體方法(已實作)」。
- 🎯 比喻: 把'動物'定義為一個抽象概念,可以說'狗'、'貓'是'動物'的衍生概念,都能進行叫(sound)的行為(抽象方法),但具體行為會不同(bark、meow);共同的行為(具體方法)像是喝水,水量作為輸入的參數。將'狗'和'貓'作為類別(Class),那麼'動物'可以是抽象類別(Abstract Class)。
2. 四大核心特性(四大支柱)
抽象(Abstraction)
🎯 比喻
駕駛使用'油門和煞車'功能時,只關心如何控制當前車速,而非引擎的運作原理,而即使替換了不同種類的輪胎,'油門和煞車'功能仍然可以運作。
📘 說明
- 抽象(Abstraction)是將具體細節概括出來的過程,將「注意力」集中在當前的目標。
- 提供使用方法,隱藏實作;即使替換了實作,使用方法仍然可以照當前預期的使用。
- 使用介面(Interface)或抽象類別(Abstract Class)描述行為,抽象(abstract)部分不提供實作。
- 低耦合,提升模組彈性。
封裝(Encapsulation)
🎯 比喻
使用電腦機殼操作電腦,這樣使用'平常的功能',是一種封裝(Encapsulation),也是一種保證;而直接操作主機板,可以做更多的操作,有的操作會導致無法正確使用'平常的功能',對於'平常的功能'就是破壞了封裝(Encapsulation)。
📘 說明
- 資料與方法封裝於同一單位內,隱藏內部資料結構或方法實作細節。
- 確保「合法狀態(資料一致性)」。
- 使用private限制外部存取、使用public的方法操作需求。
- 封裝(Encapsulation)和抽象(Abstraction)有部分共通的概念,封裝(Encapsulation)更強調的是保護物件(Object)內部,並阻止不必要的耦合。
- 要小心繼承(Inheritance)的耦合問題。
繼承(Inheritance)
🎯 比喻
如果說'狗、貓是動物的一種',那麼'狗'和'貓'就應該有'動物'的定義的所有特性,這樣獲得特性的方式,就是繼承(Inheritance)。
📘 說明
- 繼承(Inheritance)這種關聯通常反映是一種(is-a),例如'貓是一種動物'。
- 繼承(Inheritance)是一種從基底類別(base class)衍生衍生類別(derived class)的結構。
- 預期衍生類別(derived class)會自動獲得基底類別(base class)的所有屬性與方法,實現邏輯重用、組織概念層次。
- 衍生類別(derived class)可以新增或覆寫功能,但是基底類別(base class)需要規劃覆寫策略,避免破壞封裝(Encapsulation)、增加額外的耦合。
- 小心評估繼承(Inheritance)是否合理及必要,不合理的結構會導致理解困難,要將結構作為「語意」。
- 一般開發中組合(Composition)優先於繼承(Inheritance),即透過屬性或輸入參數的方式使用,而非強行使用繼承。
- 只在概念上下層次關聯明確時才使用繼承(Inheritance),也就是符合「語意」,否則使用組合(Composition)。
多型(Polymorphism)
- 同一種操作,作用於不同型別時產生不同行為。
- 有許多種類的多型,關注點不同。
Subtyping(子類型)
🎯 比喻
有許多種類的'信件','掛號信件'、'限時信件',到郵局櫃檯對於這些'信件'都可以處理寄出的動作,而實際動作有所差異。'信件'作為基底類別(base class),'掛號信件'、'限時信件'作為衍生類別(derived class)。
📘 說明
- 適用於基底類別(base class)的操作,也可以使用在繼承其的衍生類別(derived class),會有不同的行為,並且是相同的預期的作用。
Parametric polymorphism(參數多型)
🎯 比喻
預期使用'收納容器'進行'收納動作','收納容器'可以是'收納盒'、'收納櫃',對於'收納動作'只聚焦在'收納容器'。對於'收納動作',使用'收納容器'代指'收納盒'、'收納櫃'等可以收納的容器。
📘 說明
- 使用「變數」代替類別(Class),聚焦在「變數」可以進行的「動作」,這個「變數」可以是介面(Interface)。
- 在物件導向程式設計(Object-oriented programming)中有泛型(Generics),提升程式重用性。
Ad hoc polymorphism(特設多型)
🎯 比喻
有一個'開鎖'功能,可以使用'鑰匙'、'指紋'、'密碼'進行'開鎖'。'開鎖'作為方法,'鑰匙'、'指紋'、'密碼'作為「輸入參數」。
📘 說明
名稱相同的方法根據「輸入參數」不同,有不同實作,相同的預期的作用。包括:
function overloading(方法多載): 在一個類別(Class)內的同名方法,並且是不同的輸入參數組。
operator overloading(運算子多載): 重新定義如'+'、'=='等運算子行為。有時會導致誤解,例如將數字運算和文字串接放在同一個「表達式(expression)」中。
物件的關聯放到下一篇筆記。