iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
0
自我挑戰組

來讀設計模式:Junior developer 跟大家一起練功系列 第 2

DAY2: 從物件導向範型談起1

在介紹設計模式前,我們要先花點時間來介紹一下兩種程式設計:功能分解 (functional decomposition)物件導向範型 (object-oriented paradigm)

兩者的定義分別是什麼呢?我們拿本書提到的例子:

假設你是要在一個會議上擔任講師,聽課的人在課後還要去聽其他課程,但他們不知道下一堂課的聽課地點。你的責任之一,就是確保大家都知道下一堂課去哪裡上課。

接下來,我們來分析兩種程式設計會怎麼解決這個問題。

功能分解

功能分解的解決方法

若以功能分解的設計去解決這個問題,那麼會有以下的流程。

  1. 拿到聽課的人的名單

  2. 對名單上的每個人,

    a. 找到他的下一堂課是什麼

    b. 找到那堂課的上課教室

    c. 計算從你這間教室到那堂課的路線

    d. 告訴他要怎麼去那間教室

簡單來說,「功能分解」如同字面上的意思,就是將某一項功能拆解成多個子問題(多個 methods 或 functions),再將各個問題一一突破。前面這句話聽起來合情合理,但再回頭看看上面的流程,嗯⋯是不是覺得哪裡怪怪的?

問題出在哪

責任都在你身上

以程式設計的概念去解讀,這樣的方法通常會「導致讓一個『主程式』負責控制多個子程式」,使得主程式的「責任」過重。

改A錯B

每個子函數之間的互動緊密,如何互相傳遞資料?每一個函數實作的邏輯是什麼?也許還加上一堆複雜的交流,這些問題讓整個程式變成像是死的。

今天如果有個新功能要加入,例如說研究生中有擔任助教的人必須要先到行政處找行政人員辦理一些業務,你必須把這項變化新增到上面的功能裡,哇,你這樣一改下去可能會到處噴 Exception 唷!

本書提到一句話:「需求總是在變化」,這句話對於軟體開發人員真的很重要!程式不可能永遠不變,一套可以讓你撐個三五年,反過來說,在工作場域裡發生這樣的情形反而是個警訊(塊陶啊)。

低內聚、緊耦合

改A錯B以程式術語來說就是「低內聚、緊耦合」了。所謂的內聚性 (cohesion) 指的是「一個副程式中,鄰近的操作都是緊密相關的關聯」;而耦合性 (coupling) 是指「兩個副程式之間關聯的緊密程度」。

所以我們可以說功能分解可能會造成這樣的結果。

物件導向範型

將責任轉移

物件導向範型就是把關注的東西放在「物件」上。我們讓各個不同的物件做自己該做的事,每個物件對自己的行為負責,這就是「責任的轉移」。在編寫程式上,也是圍繞物件進行組織的,而非編寫函數。

物件導向範型的解決方法

針對同樣問題,使用物件導向範型去設計解決方法,會是怎樣呢?

白話來說,講師負責的事就是把這間教室到其他教室的路線圖貼出來,然後告訴課堂上的所有人:「教室路線都貼在後面佈告欄了,去找吧!」每位同學依照自己的需求,在路線圖中找到正確的教室,最後依照指示走到下一間教室。

程式面上,我們該設計的就是下列的物件:

對象 責任
Student 知道自己所在的教室知道自己下堂課的教室從一個教室到下個教室
Instructor 告訴學生下堂課的教室在哪
Classroom 有明確的地址
Director giver 在任兩個指定的教室之間,能夠給出明確的路線

軟體開發的視角、如何看待物件

本書提到 Martin Fowler 軟體開發過程中的三個不同的視角:

視角 要回答的問題
概念 軟體負責什麼?
規約 怎麼使用軟體?
實作 軟體如何履行自己的責任?

以這樣的視角框架,我們看待物件也會有三種層次。

  • 概念層次:物件是一組責任
  • 規約層次:物件是一組可以被其他物件或物件自己呼叫的方法
  • 實作層次:物件是程式碼和資料,以及它們之間往來的計算交流

學生找教室 —— 類別之於物件

更仔細地去說,對於一個 Student 物件來說,它可以有一個 method getNextClassroom() 來去找到下一間教室,而因為物件對自己負責,所以這個 method 不需要任何參數。也就是 Student 物件自己知道它需要什麼資訊以及如何完成這項任務(找教室)。

與其實作每位學生以及每位學生找教室的方法,具更高效率的設計方式會是定義一個「一般學生」,它所有學生與某一組 methods 連結起來,每位學生根據自身的需求修改這些 methods。

各式各樣的學生(物件)有著共有的 methods(包含找教室),以及一些私有的資訊(這些資訊決定他的行為)。

這個「一般學生」就是我們認知的類別 (class) 。類別是對物件行為的定義,它包含

  • 物件包含的資料元素(attributes 或 properties)
  • 物件能操作的 methods
  • 存取這些資料元素和 methods 的方式

物件就是類別的實例 (instance),舉上例來說,某個大四學生(物件)就是「一般學生」(類別)的實例。

物件導向範型在這個例子的流程

所以在這個例子裡,它的步驟如下:

  1. 開始程式

  2. 「實體化」學生的集合

  3. 告訴此集合,讓學生自己去下堂課的教室

  4. 集合讓每位同學自己去下堂課的教室

  5. 每個學生

    a. 找到自己下堂課教室在哪

    b. 決定怎麼去

    c. 去那裡

  6. 完成

在功能分解遇到的問題

我們在功能分解的設計辦法裡,碰到了「責任集中於某隻主程式上」和「低內聚、高耦合」。在物件導向範型的設計方法呢?

理論上,因為我們將責任轉移到各個學生自己(物件)身上,所以大幅度地降低主程式的權責;而每個物件都負責各自的事情,在程式面上,確實也能讓內聚性上升、耦合度降低。

接下來

物件導向範型的確能在這個例子看到它的威力,但我們尚未提到需求增加時(研究生中有擔任助教的人必須要先到行政處找行政人員辦理一些業務),上述例子該如何解決。

我會在下篇繼續講物件導向範型中「抽象類別」以及它的使用方式;還有關於物件的其他特性「封裝」、「多型」。

碎嘴:突然覺得自己寫得太細,會在過程中繼續調整⋯


上一篇
DAY 1: 一起來讀設計模式
下一篇
DAY3: 從物件導向範型談起2
系列文
來讀設計模式:Junior developer 跟大家一起練功22

1 則留言

0
gatesakagi
iT邦新手 3 級 ‧ 2020-09-18 12:13:51

寫得好詳細啊~不會瑣碎 :D

哈伯 iT邦新手 5 級 ‧ 2020-09-22 23:20:39 檢舉

感謝~~~

我要留言

立即登入留言