菜雞與物件導向 (1): 類別、物件
直覺上你當然知道什麼是物件;物件就在你的身邊。
汽車、iPhone、收音機、吐司機、廚房用具等等,你說得出來的都是。
——《深入淺出學會編寫程式》
什麼是物件?一切都是物件。
物件導向試圖讓抽象的程式碼,更貼近於我們的實際生活,其認為一切是由各式各樣的人事物互動所組成的,因此有了物件這個共通、最基本的概念。
假設現實世界存在一頭狗,叫做阿福。而我們想要在虛擬世界裡表達「有一隻叫做阿福的狗」這件事
這時候就要在系統裡有一個能代表「阿福(狗)」的東西存在,也就是「阿福」這個物件。
關於「把現實世界的物件,抽象化成程式世界裡的物件」的邏輯,可以參考 一個語言如果不改變你的思考方式,就不值得學?談程式語言的本質 這篇,尤其是選擇保留哪些資訊的部份我認為描述得很好。
現在我們知道,物件就是用來在虛擬世界中代表「某個特定的東西」,例如說叫做阿福的狗就是一個物件,阿福今天晚上要吃的飼料罐也是一個物件。
理解物件的概念是相當直覺且迅速的,畢竟你我身邊有著數不清的東西,它們都是一件一件的物件,但這樣的理解還不夠明確。
就像前文所引的 談程式語言的本質 文中所提到的,在抽象化的同時我們必然要選擇保留哪些資訊。
例如說阿福這隻狗,是一個物件;飼料罐也是一個物件
而這些物件之間還會彼此互動,例如說阿福是一隻狗,而我們觀察到狗都有吃東西這個動作,例如「阿福吃了飼料」
同時物件也會有一些專屬於它的特徵,例如說阿福是黑色的,我們就知道狗有毛色的差別。
那麼我們要怎麼表達「阿福」作為一隻「狗」擁有的那些動作和特徵呢?狗的毛色?狗可以吃飼料?
我們需要選擇怎麼去描述「狗」--也就是阿福這隻狗,被我們抽象化後的樣子,我們需要將它用程式碼的方式定義出來。
這時候我們就會需要類別,來定義出我們觀察到同一類的物件該有哪些特徵和動作,也就是我們替物件「分門別類」後、篩選出特定資訊的抽象化結果
延續前面的例子,假設今天我們從阿福身上觀察到進食跟毛色兩個狗的重要資訊,我們就可以建立類別 Dog:
public class Dog
{
public string color;
public void Eat(IFood food) { /* 進食與消化之類的 */ };
}
藉由我們定義的類別,就可以從類別中實例化(=建立)出物件。
也就是說,現在我們終於可以用「狗」這個類別,來表達出我們需要的「阿福」了:
Dog afu = new Dog(); // 阿福是一隻狗
Console.Write(afu.Color); // 阿福是黑色的
afu.Eat(food); // 阿福會吃食物
類別最常看到的比喻,就是物件的設計圖。我們藉由類別去定義我們要的物件有什麼特徵、有什麼功能,再從類別根據設計圖產生物件出來使用。
這個從類別中產生的物件,就等於是這個類別定義的一個實際的例子,所以我們也會把類別產生的物件叫做實例。而從類別產生物件的過程,就叫做實例化。
也就是說,類別實際上就是我們認知中對這個物件的定義,我們篩選出我們需要的、我們認為這個物件應該具有的這些特徵和功能,按照我們的認知去設計了類別
接著我們再利用這個類別告訴程式如何建立出我們認為的這個物件,最終我們才能在程式中使用我們需要的這個物件。
當我們定義了一個狗的類別,我們實際上是在描述我們眼中的、我們歸納出來的、我們需要的「狗」,我們認為狗就是會吃東西。
接著,我們再從我們設計好的這份定義,去實例化出我們需要的狗:阿福,於是阿福就有了吃東西的能力。
我們有了抽象化的設計圖之後,就可以利用這個設計圖去建立多個符合這個設計的物件。例如說前面的狗,我們就可以建立出黑色的阿福,黃色的阿黃等等。
在現實中,我們將阿福、阿黃等等歸類為狗這個概念,而到了程式裡,我們利用這個狗的概念定義出類別,進而產生阿福、阿黃。
從這邊也能察覺到:類別是一個歸納好的概念,這概念中包含許多獨立的個體,也就是物件,而這些物件之間的差異則從我們定義類別時選擇的特徵去區分。
因此,一個人設計的類別,和他使用物件的方式,反映了他對於這個物件的看法和他覺得需要的內容。
同時,使用物件導向也意味著:比起 EatFood(dog, food)
而言,我們認同 Dog.Eat(food)
更直覺和易於理解。
那麼這邊就讓我們以卡牌遊戲舉例,理所當然卡牌遊戲不能沒有卡牌。
對我來說卡牌通常都需要這些特徵,我們在物件裡稱為屬性:
- 卡片名稱
- 攻擊力
- 防禦力
- 卡牌描述
等等,另外卡牌也應該能作出某些動作,也就是這個物件的方法:
- 攻擊
我們確認了這些要素以後,就可以把它設計成一個類別 Card
如下
public class Card
{
public string Name;
public int Level;
public int Attack;
public int Health;
public string Description;
// 攻擊目標卡片
public void Hit(Card target)
{
target.damage(this.Attack)
}
// 被攻擊的時候扣血
public void damage(int attack)
{
this.Health -= attack;
if (this.Health <= 0)
{
/* 可能呼叫死翹翹方法? */
}
}
}
抱歉我菜,如果有真的設計卡牌遊戲的工程師經過拜託不要打我。
接著我們就能在需要的時候藉由這個類別來實例化我們的卡牌:
var goblin = new Card();
var warrior = new Card();
warrior.Hit(goblin);
再提醒一次:
- 類別是定義、是設計圖、是描述;物件是類別產生的實體、是實際上的執行者
- 類別是抽象化的資訊,例如「狗」;物件則是一個特定的實例,例如「叫做阿福的狗」
- 承上,狗的類別用來告訴程式什麼是狗;叫做阿福的物件則是程式根據我們的指示,建立出來的一條指定的狗
到此應該能夠初步掌握物件和類別的概念了。這邊推薦一下可以閱讀保哥的這篇 物件導向基礎:何謂類別(Class)?何謂物件(Object)?,裡面除了對物件和類別有更易懂的介紹和舉例以外,還有十題概念題可以幫助你搞懂物件和類別的意義與差異,相當值得一看。另外,也可以參考這幾篇的說明:
物件的部份由於是最初的概念,不免多廢話了一些。下一篇開始就讓我們快速看過物件導向的幾項功能和特性。
本系列下一篇:菜雞與物件導向 (2): 建構式、多載
2022.12.02 補充:感謝公司前輩簡潔有力的說明,修正了開頭時對物件的介紹
參考資料
- 一個語言如果不改變你的思考方式,就不值得學?談程式語言的本質
- 物件導向基礎:何謂類別(Class)?何謂物件(Object)? - The Will Will Web
- 有物件導向的世界與沒有物件導向的世界
- Java 物件導向的概念 - 菜鳥工程師肉豬
- Object Oriented物件導向-1:類別(Class)與實體(Object) - Sian
- [C#] 物件與類別 - Yehyen’s Notepad
- 物件導向程式設計(C#) - Microsoft Docs
- 物件導向(Object Oriented Programming)概念 - Po-Ching Liu - Medium
- 《大話設計模式》附錄:物件導向基礎
- 《深入淺出學會編寫程式》Ch7:模組、方法、類別以及物件
同系列文章
- 菜雞與物件導向 (0): 前言
- 菜雞與物件導向 (1): 類別、物件
- 菜雞與物件導向 (2): 建構式、多載
- 菜雞與物件導向 (3): 封裝
- 菜雞與物件導向 (4): 繼承
- 菜雞與物件導向 (5): 多型
- 菜雞與物件導向 (6): 抽象、覆寫
- 菜雞與物件導向 (7): 介面
- 菜雞與物件導向 (8): 內聚、耦合
- 菜雞與物件導向 (9): SOLID
- 菜雞與物件導向 (10): 單一職責原則
- 菜雞與物件導向 (11): 開放封閉原則
- 菜雞與物件導向 (12): 里氏替換原則
- 菜雞與物件導向 (13): 介面隔離原則
- 菜雞與物件導向 (14): 依賴反轉原則
- 菜雞與物件導向 (15): 最少知識原則
- 菜雞與物件導向 (Ex1): 小結
其他文章
哈囉,如果你也有 LikeCoin,也覺得我的文章有幫上忙的話,還請不吝給我拍拍手呦,謝謝~ ;)