物件導向是什麼?|JavaScript 四大物件特性簡介|初學者筆記(1)
更新日期: 2023 年 3 月 1 日
閱讀要求:
「物件導向」屬於一種進階的程式設計概念。
如果你想要看懂本文的內容,建議先對以下內容有基本認識,才能更容易閱讀本文的內容:
- 知道「函式」是什麼,如何「使用函式」
- 知道「資料型態」與「變數」是什麼
什麼是物件導向程式設計?
根據當我們搜尋「物件導向程式設計」(Object Oriented Programming,簡稱 OOP)時,通常都會達到類似以下的解釋:
它將物件作為程式的基本單元,將程式和資料封裝其中,以提高軟體的重用性、靈活性和擴充性,物件裡的程式可以存取及經常修改物件相關連的資料。
引述來自《維基百科》
作為一個程式初學者,通常第一直覺都是:「到底在寫什麼碗糕」。
因此,容我們換個更容易理解的方式,去認識物件導向的概念。
我們以 Google 這間公司為例。
Google 旗下有各式各樣的軟體服務,如:google 搜尋、google 地圖、google 日曆、Youtuebe 等等。
如果我們將這些服務的程式碼相加,它一共約有 20 億行程式碼需保存,並且讓全公司 2 萬 5 千位員工維護並更新。
對此,我們需要藉由有條理與有秩序的方式,將程式碼好好的收納並安排整齊。
首先,我們第一個可以想到的方法就是透過「函式」,將他們分裝組合起來。
假設一個函式可以保存 10 行程式碼,就能將 20 億行程式碼拆成 2 億個函式。
當然,對我們來說 2 億個函式,也是一個龐大的數量。
這時就需要使用另一個更大的容器,將函式打包起來,此做法就稱為:「物件」。
我們可以使用物件,將數個函式通通收納到同一個區塊。
假如一個物件可以收納 100 個函式,這樣就能將 2 億個函式拆成 200 萬個物件。
相較於原先的 20 億行程式碼,200 萬個物件已經容易維護許多。
因此,我們換個方式重新解說一次物件導向
你可能想說 200 萬還是太多了,該怎麼辦?
這還不簡單,如果物件無法將程式碼分類完全,那我們為何不再用「更大的物件」將其打包。
例如:大大大物件 -> 大大物件 -> 大物件 -> 物件 -> 函式-> 程式碼。
最後程式碼就能透過函式與物件,讓它像俄羅斯娃娃一樣不斷被打包收納與整理。
上述這種將程式碼透過不斷物件打包、分類的過程,就稱為「物件導向」。
因此,其實「物件導向」的本質,其實就是一種管理程式碼的「管理方法」。
當我們理解物件導向的概念後,再套用到實際的程式碼中,就能理解對應的概念。
當然,以上的內容只是簡短的介紹,物件導向程式設計其實具備以下四種重要概念:
- 封裝(Encapsulation)
- 提煉(abstraction)
- 繼承(Inheritance)
- 多型(Polymorphism)
接下來,將為你們仔細講解相關意涵。
封裝(Encapsulation)
未使用物件導向概念以前
通常我們一開始學習 JavaScript 時,會用「變數」儲存資料,用「函式」執行動作。
此外,我們還會知道程式語言處理問題時,是將大問題猜解成小問題,並針對各自的小問題撰寫對應的功能函數。
當每個小困難都順利被解決時,整體問題也會一併迎刃而解。
上述這種拆解問題的過程,也是計算機科學的一個重要方法:功能分解(functional decomposition)。
對於初學者來說,上述的編程方法非常簡單與直觀。
但問題是當程式碼變得越來越長、複雜時,為了要調用散落在各處的函數與變數,讓管理與後續維護變得異常困難。
例如,每當有一個新功能要加入原有代碼中時,就需要先釐清函數之間的關係,才不會產生改 A 錯 B 的現象。
具備物件導向概念後
物件導向程式設計,就是要改善上述所列的問題。
它透過將性質相同的變數與函數,放進同一個「容器」中,用以區分不同特性的代碼。
此外,我們將每個物件中變數與函式都稱為物件的「成員」。
如果該成員是變數的話,就會被稱為「屬性」(property),如果該成員是函式,就被稱為「方法」(method)
舉例來說,如果我們今天想要建立一個「黑崎一護」的物件。
它的屬性就會有「姓名」、「穿著」、「死神執照」等等。
它的方法則會有月牙天沖、瞬步、卍解等等。
如果以實際程式碼來看,假設我們有個計算薪資相關的代碼。
let baseSalary = 26,400; //底薪
let overtime = 10; //加班時數
let rate = 176; //每小時加班費
function getWage(baseSalary, overtime, rate){
return baseSalary + (overtime*rate); //薪資加總
}
getWage(); // 執行函式,計算薪資
如果我們將上面的程式碼「封裝」,則會得到一個「員工」的物件,並且呈現方式改成以下顯示:
let employee = {
baseSalary: 26,400, //底薪
overtime: 10, //加班時數
rate: 176, //每小時加班費
getWage: function(){
return this.baseSalary + (this.overtime*this.rate); //薪資加總
}
}
employee.getWage() // 執行函式,計算薪資
這段程式碼「封裝前」與「封裝後」,最大的差別在於函式的「參數數量」。
在未封裝前,薪資加總的函式一共有三個參數,分別有三個參數:
- 底薪參數
- 加班時數參數
- 加班費參數
但當我們使用物件封裝後,可以使用物件特有的功能關鍵字「this」語法,讓電腦知道物件中的成員彼此相關。
因此將薪資加總的函式參數瞬間歸零,變成一個更簡單、易使用的參數。
最好的函式,就是沒有任何參數。
Robert C. Martin
提煉(abstraction)
「提煉」是物件導向中非常重要的概念,他會幫助我們將原有包山包海的程式碼中,提取出真正重要的部份讓人使用。
我們以實際情境為例,每個人的手中都有一台智慧型手機,通常它大概只有三個按鈕:開機、音量大聲、音量小聲。
這種設計模式,幫助我們隱藏這台手機的複雜性。
讓使用者能更用正確、輕鬆的方法與這台手機互動,而不用去理解手機內部複雜的電線迴路設計。
同理,套用回程式碼中。
原本包含數個函式變數的物件,透過「提煉」將一些對使用者不重要的內容隱藏,只保留重要的部分。
這種作法,不僅讓使用者能正確的操作物件,選擇適當的方法與屬性。
同時,因為只有顯示部分的物件成員,能避免因為使用者操作不當,導致物件內的其他成員連帶受影響。
繼承(Inheritance)
當我們在建立物件時,有時候會遇到物件具備相同的屬性與方法,只差在「值」不同而已
一般來說,程式新手都會使用「複製、貼上大法」,如果有幾個的物件就複製貼上幾次
但更簡單的方式,是使用物件導向的「繼承」特性。先設定一個公版的物件代碼,再以此創建相近性質的物件。
這種方式可以讓程式碼的冗長程度降低,並增加效率。
例如,如果我們想要建立一個法鬥與吉娃娃的物件。
由於它們都具備相同的屬性與方法,可以先建立一個公版的「狗」物件,並以該物件為基礎,各自提供對應的值,就可以建立完成。
多型(Polymorphism)
有些時候,我們有些函數的名稱可能會類似,但實際執行的作用卻不相同。
我們繼續以狗狗為例,當狗狗見到主人時,都一定會有「見到主人」對應的反應。
但此行為會隨著不同品種、不同個性的小狗,而有不同內容的實際作為。
function 法鬥見到主人的反應(){
// 不理人之類的...
}
function 吉娃娃見到主人的反應(){
// 亂叫之類的...
}
function 柴犬見到主人的反應(){
// 搖尾巴之類的...
}
在使用物件之前,我們會需要寫各式各樣的條件判斷式,例如 if、switch 等等語法,去區分不同情況應該適用何種函式
if( 狗 == 法鬥 ){
法鬥見到主人的反應();
} else if( 狗 == 吉娃娃 ){
吉娃娃見到主人的反應();
} else if( 狗 == 柴犬 ){
柴犬見到主人的反應();
}
但當我們使用「物件」將相近的變數與函式歸類在一起時,就可以免除上述複雜的判斷條件。
例如下方有三個不同品種的狗狗物件:
如果我們想要增加見主人的函示,只要各自新增一個名稱相同方法。
當我們實際應使用時,只要藉由引用物件的方法,就可以輕易完成函數的使用,也不用再去思考各式各樣的函式名稱與判斷條件。
法鬥.見主人(); //法鬥見主人的反應
吉娃娃.見主人(); //吉娃娃見主人的反應
柴犬.見主人(); //吉娃娃見主人的反應
而此方法就稱為「多型」,同一個命名卻能有多種形式的展現。
概念總結
以上四個基本觀念,就是物件導向程式設計所帶來的好處。
最後,讓我們再次總結四大特性。
- 封裝:降低複雜程度 + 增加可重複使用性
- 簡化:降低使用難度門檻 + 保護區塊重要資訊不受影響
- 繼承:減少重複相近的程式碼
- 多型:重新打造複雜的條件判斷式
以上就是這次分享的內容,感謝收看!
系列文章統整
- 物件導向是什麼?|JavaScript 四大物件特性簡介|初學者筆記(1)
- 如何建立物件?|JavaScript 初學者筆記(2)
- 什麼是原型(Prototype)?|JavaScript 初學者筆記(3)
- 類別(class)是什麼?|JavaScript 初學者筆記(4)
問題統整
假設一個函式可以保存 10 行程式碼,就能將 20 億行程式碼拆成 2 億個函式。
當然,對我們來說 2 億個函式,也是一個龐大的數量。
這時就需要使用另一個更大的容器,將函式打包起來,此做法就稱為:「物件」。
其實「物件導向」的本質,其實就是一種管理程式碼的「管理方法」。
例如:大大大物件 -> 大大物件 -> 大物件 -> 物件 -> 函式-> 程式碼。
最後程式碼就能透過函式與物件,讓它像俄羅斯娃娃一樣不斷被打包收納與整理。