邁向熟手之路 - 物件導向程式設計

2024/04/08閱讀時間約 6 分鐘


在上一篇文章我們有聊到過程式設計的三個基本要素,循序、選擇、迴圈。只要掌握這三個觀念,不管你用哪種程式語言你都能很好的基礎入門。我自己經過這麼多年的觀察與實踐,一個成熟的軟體工程師還需要第四個要素「物件導向程式設計」,它是讓決定你通往熟手的重要關鍵沒有之一。

物件導向程式設計

早期我們學程式設計的時候都是使用 「功能分解」 的觀點來構建程式,所謂的功能分解就是把業務流程的每一個動作按照先後順序全部拆解出來,也就是以「萬物皆動作」的觀念來設計程式。具體的狀況是先畫好流程圖後再開始 coding ,流程圖內會標示起點到終點,主程式從頭到尾負責所有動作是一個不可分割的整體。

物件導向程式設計採取的策略是改用「萬物皆物件」的觀點來寫程式,跟功能分解最大的差異是把的業務流程按照責任分工拆解出不同任務需求的角色物件,靠物件間的互動關係來設計程式,工具上改用 UML 來表達程式裡面的物件繼承架構與互動關係,分而治之可謂是物件導向設計的核心。

分而治之是物件導向設計的核心。


好的封裝從觀察開始

要進入物件導向設計須要從封裝開始。關於封裝,通常程式設計書大概會這樣描述:

把一個或多個 data 跟 method 放進一個 class 裡面

這是單純從程式語言的角度、從字面上最直接的解釋,精準但幫助有限。因為要如何選擇哪些 data 跟 method 放在一起取決於你要解決的問題,作者只能站在教學的立場嘗試給出一些通則範例,不是太過簡單就是通常都離你的問題很遠,所以學習階段不用過度糾結。

不需要糾結遠離問題核心的範例

我們真正要做的是借用封裝的原則來仔細審視你的問題,嘗試辨識出潛藏裡面的各種物件,找出它們的特性跟能力與彼此該如何互動的關係,分析過程有點像是寫 pseudo code 需要先把想法邏輯整理起來,最後才是去對照你選用的程式語言的語法轉換成 data 跟 method 然後封裝到對應的 class 裡面。只有這種方式定義出來的 class 們才會對你的設計產生意義,實體化出來的物件才有了解決問題的能力。

「仔細審視你的問題,嘗試辨識出潛藏裡面的物件」是站在上帝視角看問題

在小朋友過馬路場景裡面除了小朋友以外,還會有馬路、周邊住家商店、往來的車輛跟交通號誌等”物件”,關鍵”物件”就是我們解決問題過程中必須要辨識出來的對象。我知道有些人鉅細靡遺,觀察的畫面非常豐富,記住一個最小設計原則,只需要把關鍵物件辨識出來然後封裝到所需的類別裡面去就可以了。

運用最小設計原則找出關鍵物件


能見度決定封裝品質

經過仔細觀察分析問題後你已經找出關鍵物件以及它們之間的運作關係,那麼決定封裝品質依據是什麼呢?答案是能見度。

每個封裝進 class 裡面的 data 或 method 特性值都還要加上 private public 等能見度設定。我認為一個好的封裝品質要有最低的能見度,就像封裝手機一樣嚴密結實完全地不透明,只需要提供人機介面來互動即可,使用者並不需要手機裡面的結構、線怎麼 layout 的對使用者來說並不重要也不需要知道,不需要暴露出來。看不到設計細節這點對只習慣功能分解設計的人會需要花時間來適應。習慣後慢慢改變你看事情的觀點,也會發現你的設計變得越來越自然,

手機是品質良好的封裝典範


繼承是體系也是規範

繼承最常被拿來討論的觀點是 Reuse,要是把 Reuse 講成了是繼承的唯一目的就有點狹隘了。相較前面封裝是觀察找出物件,繼承是為了將找出來的物件們進行分類歸納,嘗試找出物件之間共同點來建立新的 class 確認彼此的上下關係練。找出共同點,找出物件共同意義上的集合當作父類別,並依此作為繼承關係的標的。

繼承體系是物件間的上下關係鏈

還是那個小朋友過馬路的例子,上學時間會過馬路的不只是小朋友,而是有國小生、國中生和高中生。此時學生類別就很適合當作它們共同的父類別,當上班族等其它非學生的族群也加入後,就需要的更適合的行人類別 (上班族跟學生族都是行人的子類別) 來當作基礎類別。整理的關鍵就是找出把他們的共同部份抽出來定義成父類別,過程中不斷的利用 「is a, has a」 來確認,最終在你的設計方案裡成為一個完整的繼承體系。

可以被繼承的東西技術上也可以是半實作的抽象類別或是完全不實做的抽象介面來繼承,可以把這種抽象類別或介面想成一組規範或能力,所有的子類別都要實作父類別所指定的能力(或者說,只有完全具備要求能力才屬於這個類別),所以在遊戲軟體設計裡面可以創造出各種非現實的物體,例如會飛行跟噴火能力的烏龜,只要讓那隻烏龜物件繼承並實作了飛行跟噴火的介面就可以了。

抽象類別是規範或能力的組合


多型才是真實應用型態

再回到小朋友過馬路例子,如果使用功能分解的設計,主程式必須完全掌握每一個小朋友的各種特徵與運動能力,還要嚴格規定過馬路的每一個動作,從該站在哪個位置、起步要左腳先還是右腳先、每一步要走多少距離,要用多快速度移動等全部都要主程式來決定,可以做到但與現實不符!

現實中是不可能知道每個小朋友特徵與能力的,此時怎麼辦呢?很簡單,就來觀察小學老師怎麼做。首先老師會先讓要過馬路的小朋友們不分年級全部集合排成一列,使用「同學」稱呼所有的小朋友,透過同學這個介面來下達「同學們開始過馬路」指令,然後每個小朋友收到指令後很自然地用自己的方式就開始過馬路了。

學生與行人都會自己過馬路

老師使用「同學」的方式來控制各種不同小朋友個體的方法就是多型應用,負責控制流程的老師並不需要知道隊伍裡面的每個小朋友個體狀況,所有的同學都有過馬路的能力,而小朋友們都是這個類別的實體,自然都具備自己過馬路的能力,而在主程式裡面使用多型設計才是我們使用繼承的真正目的。

多型應用才是繼承的真正目的


小結

好了,講完啦。是不是感覺物件導向的觀念還是有點很困難且複雜?!確實物件導向設計的門檻很高,但也具備更好的投資價值。學會物件導向設計觀點後自然會更注重整體架構、物件完整性還要顧慮彼此互動關係,當然設計過程也會充滿挑戰性,特別是你的邏輯推演、歸納物件、概念抽象化的能力。

還有 UML 也是物件導向設計必備的工具,特別是再跟團隊合作的時候特別有感。進化過程需要時間且辛苦的,當你真正學會用「萬物皆物件」的觀點就能設計出「最自然且符合人性」的程式,你的程式運作起來會更貼近真實的世界。附帶的好處還有實現分而治之的高內聚、低耦合的設計,也會讓你的程式規模可以更大又更好維護。最後,再把眼光放遠一點,將來還有機會繼續升級到更高階的設計模式,真正進入架構設計領域了。

9會員
58內容數
WarrenLo's 軟體設計武功祕笈
留言0
查看全部
發表第一個留言支持創作者!