多型(Polymorphism)&繼承(Inheritance)能解決什麼問題? — 用 TypeScript 學物件導向
市面上很多文章、影片分享了物件導向要如何應用。
卻很少人分享這些概念最初是為了解決什麼問題,所以很多人就算學完了物件導向的概念,卻依舊沒有把它應用在手上的專案。
因此這個系列文中,筆者會先分享「直線思考下」我們會設計出怎樣糟糕的程式;接著再來討論如何應用物件導向的概念對程式做 Refactoring,提升程式未來的擴充性、維護性。
大綱一、建立一個讓不同職業交流的平台二、老闆想要再多加幾個職業三、[Refactoring]將「介紹技能」程式移轉到 Class 變成 Function四、平台經營的很成功,要擴增「技能交換、讀書會」的功能五、[Refactoring]老闆…我改不動了,打算用繼承進行重構六、應用多型讓不同職業的工作者進行交流七、所以「多型(Polymorphism)&繼承(Inheritance)」的概念幫我們解決了什麼問題?
一、建立一個讓不同職業交流的平台
既然要建立不同職業交流的平台,那工作者就是必不可少的元素;我們先建立一個「工作者(Worker)」的 Class,並設計「name(姓名)、jobType(職業類型)」作為屬性。
因為這個系統只是試水溫的階段,所以在一開始只開放「工程師(ENGINEER)、設計師(DESIGNER)、律師(LAWYER)」這幾個職業(Job),我們用列舉(enum)的方式來實現。
在 Worker 的 Class 建立完後,我們便可以將對應的「職業」實體化;既然我們要讓不同的職業進行交流,就模擬一小段讓他們「介紹技能」的程式。
二、老闆想要再多加幾個職業
系統上線後反應熱烈,老闆希望再新增「魔術師(MAGICIAN)、畫家(PAINTER)」這兩個職業,於是我們在 Job 裡面新增這兩個職業的常數。
在 Worker 的 Class 調整完畢後,我們也要同步調整讓工作者「介紹技能」的程式。
我想程式寫到這裡,應該有很多人發覺不對勁了,如果每新增一個職業,我們就要在另一個檔案中調整程式,這樣伴隨系統的成長,我們會越來越難維護它。
三、[Refactoring]將「介紹技能」程式移轉到 Class 變成 Function
為了避免日後我們要在多個地方維護程式,我們把判斷職業的 switch 轉移到 Worker 的 Class 中,並新增一個「introSkill」的 Function 讓外部使用。
經過上面的調整後,不同職業的工作者如果想「介紹技能」,呼叫 introSkill 的 Function 即可。
四、平台經營的很成功,要擴增「技能交換、讀書會」的功能
為了讓各行各業交流的更加熱烈、深化自身技能,老闆請你增加「技能交換(skillExchange)、讀書會(studyGroup)」的功能,如果你依照原本的邏輯繼續設計程式會長這樣。
我們現在才 5 個職業、3 個功能就把 Worker 這個 Class 搞的這麼冗長了,現在先來分析這個程式日後會遭遇的問題:
- 維護性:日後增加新的職業,需要在每個 switch 設計對應的 case;如果職業繁多,那產生 Bug 是完全可以預期的事情。
- 可讀性:如果這個平台由多位工程師共同開發,那其他工程師使用到 Worker 這個 Class 時可能會很抖,因為無論閱讀理解還是改寫都很困難。
- 擴充性:如果未來需要根據特定職業設計獨有的 Function(比如只允許工程師使用 Programing),那可能就要動到 Class 的結構了。
五、[Refactoring]老闆…我改不動了,打算用繼承進行重構
既然我們已經體會到「新增職業」帶來的痛苦,不如先用繼承的概念重構,將「工作者(Worker)」設計為基礎類別(父類別)。
因為職位有「多樣性」,所以我們將 Worker 定義為「抽象類別(abstract class)」,並將「skill、skillExchange、studyGroup」這些功能抽象化,讓繼承的衍生類別(子類別)去實現。
日後我們想新增一個職業時,只要讓他繼承「工作者(Worker)」的 Class,並實作抽象的功能即可;下面舉一個新增「工程師(Engineer)」這個職業的例子。
程式重構後,我們新增職業不但變得輕鬆,還大幅降低產生 Bug 的風險;因爲繼承 Worker 的 Class 後,會明確告訴你需要實作的功能有哪些(如果沒有實作就會報錯😅)。
六、應用多型讓不同職業的工作者進行交流
接著我們回到讓不同職業的工作者「介紹技能」的程式。
這次我們在陣列中塞了兩種職業(Engineer、Designer);不過因為這些職業都是 Worker 的衍生類別,所以在 forEach 中我們可以用「Worker」進行解析,進而存取 Worker 所提供的方法(introSkill)。
備註 1:如果今天我們在工程師(Engineer)的 Class 新增 programming 的方法,那這個方法在 forEach 裡面是無法使用的(因為裡面僅允許 Worker 的方法)。
備註 2:如果我們今天在陣列中增加一個並非 Worker 的衍生類別(ex:new Animal()),那 forEach 會因為偵測到你放了非 Worker 的衍生類別而報錯。
七、所以「多型(Polymorphism)&繼承(Inheritance)」的概念幫我們解決了什麼問題?
這邊筆者就分享自己使用下來最直觀的感受:
- 繼承的概念讓我們的程式可以被重複使用。
- 多形的概念幫我們把功能抽象化,根據實際的需求去執行。
參考資源:Java物件導向 重觀念迅速教學 3 Polymorphism 什麼是繼承? 什麼是多型?為何多型以及如何設計多型?
▶︎ 用 TypeScript 學物件導向▋ 封裝(Encapsulation)能解決什麼問題?
▋ 多型(Polymorphism)&繼承(Inheritance)能解決什麼問題?(本篇)▶︎ 如果這篇文章有幫助到你1. 可以點擊下方「Follow」來追蹤我~
2. 可以對文章拍手讓我知道 👏🏻你們的追蹤與鼓勵是我繼續寫作的動力 🙏🏼▶︎ 如果你對工程師的職涯感到迷茫1. 也許我在iT邦幫忙發表的系列文可以給你不一樣的觀點 💡
2. 也歡迎您到書局選購支持,透過豐富的案例來重新檢視自己的職涯