--- tags: 視窗程式設計 --- # 類別與物件的觀念 如果你開始感受到函式的好用,可以大幅度減少高度類似的程式碼,還能進一步讓程式更精簡,接下來你就可以進一步了解「類別與物件」。 首先,我們幫同學建立「類別」的概念,當你開始學習類別,你就開始入門 **物件導向程式設計(Object-Oriented Programming, OOP)** 了。 :::success **恭喜你,開始脫離程式新手村。** ::: 第一次聽到類別這個東西,你一定覺得很難理解這是甚麼?沒關係,我們慢慢來,先從日常的範例想像一下: ## 假設你要騎一台機車 如果你要騎一台機車出門兜風,那要怎麼做呢? :::info 交通安全宣導:請同學務必考取駕照後再上路。 ::: 1. 你需要先幫機車加足夠的汽油 2. 跨上車,將鑰匙插入鑰匙孔,啟動引擎 3. 轉油門手把,機車就會加速往前跑 4. 如果速度太快,要放鬆油門手把,適度拉剎車手把 **以上應該你都可以理解吧?** 如果可以理解的話,你應該可以理解所謂類別的觀念。 :::info 「類別(Class)」是將生活中事物「抽象化」,或者我們將抽象化改稱為「簡化」也可以。 ::: 現在我們將一台機車的功能與狀態「簡化」一下,請參考下圖: ![](https://i.imgur.com/81eznvM.png) 因此一個機車的「類別」,你可以看成就是機車的簡化概念,其中類別可以分成「**屬性(Property)**」與「**方法(Method)**」。 * 屬性:定義類別的特性 * 方法:定義類別可操作的工作 用比較簡單的方式來解釋屬性與方法。 :::info 1. 你需要先幫機車加足夠的汽油:**設定油箱屬性** 2. 跨上車,將鑰匙插入鑰匙孔,啟動引擎:**設定鑰匙插孔屬性** 4. 轉油門手把,機車就會加速往前跑:**執行油門方法** 5. 如果速度太快,要放鬆油門手把,適度拉剎車手把:**執行剎車方法** ::: 因此類別就是一種將日常事物「抽象化」或「簡化」的方式,你或許不太習慣,以後可以多練習,把生活中的事物也用類似的方式簡化,就會慢慢習慣類別的概念。 ## 寫一個程式的類別 了解基本的類別概念之後,我們就直接實作,這樣更能加深你的印象。 我們繼續使用之前的**計算機程式**,將它原本計算機進行計算邏輯的部分獨立出來,變成類別,這樣更能將程式變得更有結構。因此請開啟上一章節完成的計算機程式專案,我們繼續用這個專案當範例。 首先我們跟同學介紹如何在 Visual Studio 新增一個類別的程式檔,通常它可以放在一般程式碼裡面或者獨立一個檔案,這邊我們介紹如何將類別寫成獨立檔案。 :::info 寫成獨立檔案的好處就是,你可以直接在把這個檔案複製到另一個專案檔裡面,很簡單的直接使用。 ::: ![](https://i.imgur.com/2O6qLTj.png =600x) 看大圖:https://i.imgur.com/2O6qLTj.png 新增一個類別檔案的方式,請在方案總管中點選你的專案名稱上面按右滑鼠鍵,選擇加入 -> 新增項目。 ![](https://i.imgur.com/ePvLrnE.png =600x) 看大圖:https://i.imgur.com/ePvLrnE.png 接著就會出現這個視窗,請確定有沒有選到類別的項目,然後名稱取名為「Calculate.cs」,名稱一樣不要用中文或違反命名規則,最後按新增的按鍵。 ![](https://i.imgur.com/AaiN7VJ.png) 完成之後,你就會看到方案總管中有這個類別檔案了。對這個檔案點兩下開啟,再新增以下的程式碼。 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Calculator { class Calculate { public float firstNumber { get; set; } = 0; // 屬性:firstNumber 儲存第一個數字 public float secondNumber { get; set; } = 0; // 屬性:secondNumber 儲存第二個數字 // 相加方法 public float Add() { return firstNumber + secondNumber; } // 相減方法 public float Subtract() { return firstNumber - secondNumber; } // 相乘方法 public float Multiply() { return firstNumber * secondNumber; } // 相除方法 public float Divide() { if (secondNumber == 0) { throw new DivideByZeroException("Cannot divide by zero."); } return firstNumber / secondNumber; } // 重新設定方法 public void Reset() { firstNumber = 0; secondNumber = 0; } } } ``` ### 說明 你可以仔細看一下以上的程式,其實很多語法你都看過了,例如屬性,其實有點像是宣告變數,方法則是一般的函式。然後你可以注意到,幾乎它們都是 Public 公開的,換句話說,因為有可能類別要被別的程式所使用,所以很多都是用 Public。 我們把以上的計算機類別程式(Calculate.cs),以類似機車類別的方式,整理成下表的形式。 ![](https://i.imgur.com/NUFzDsZ.png) 你可以不要先看程式內容,先看這張表格,就可以大致了解這個計算機類別可以做甚麼?並且如果你還記得計算機程式的執行邏輯,其實也是這個類別可以完成的。 :::info 1. 輸入第一個數字:**將數字存在屬性firstNumber** 2. 輸入第二個數字:**將數字存在屬性secondNumber** 3. 按等於按鍵:**執行特定的四則運算方法** 4. 按AC按鍵:**執行重新設定方法** ::: ### 類別其實有點像是海軍命名船舶常用的「船級」名稱 例如第二次世界大戰美國的有名戰艦艦級「**愛荷華級(Iowa-class Battleship)**」,**愛荷華級代表的是某個型號的戰艦**,因此會有數艘同型的戰艦,歷史上愛荷華級的戰艦包括:愛荷華號、紐澤西號、密蘇里號、威斯康辛號(還有兩艘沒有完成的)。 「類別」就類似某種型號的戰艦,只要是同一型號的戰艦,都會有類似的型態,這些戰艦就是根據類別製造出來的「物件」,之後我們會把這個概念繼續在「物件」中進一步說明。 ![](https://i.imgur.com/rRvyOaO.jpg) ## 簡單的結論 類別的設計,你可以用一個整體的思考方式,來規劃程式的架構。 例如計算機程式,你可以將原來的程式邏輯,分別依照屬性與方法的概念做一個整理,再將這些程式整理成類別來使用。你可以更好的修改或調整程式,如果是其他的程式設計師也可以方便的用你寫好的類別。 甚至我們可以將屬性與方法的使用方式說清楚,別的程式設計師可以不需要深入了解你的程式內容,只要知道有甚麼屬性與方法?知道這些屬性與方法如何使用?他們就可以快速的將你的程式用在他們的專案。 :::info 何時需要做類別?老師多半都在整理程式的階段來做。 ::: ## 類別可以用來建立物件 一開始跟同學介紹 **物件導向程式設計(Object-Oriented Programming, OOP)** ,那麼類別(Class)與物件(Object)有甚麼關係?以下用例子說明這兩者的差別: :::success * **類別**:是一個藍圖、範本、概念的設計,類別必須要 **實體化(Instance)** 成物件才能使用。 * **物件**:是一個看的到、摸的到的實體。 ::: 如果舉蓋房子為例。 :::success * **類別**:**建築設計藍圖**,決定房子的格局,有幾間房間?結構為何?只是規畫的設計圖,不能真的住進去。 * **物件**:**實際蓋好的建築**,照著設計藍圖所蓋出來的,並且可以住進去與使用的。 ::: 如果以機車為例。 :::success * **類別**:**機車設計圖**,決定機車的基本設計,設定引擎、輪胎、傳動等大小零件怎麼安裝,不能真的拿來騎。 * **物件**:**實體的機車**,照著設計圖製造與組裝的機車,可以真的拿來騎車。 ::: 所以我們剛剛做好的**計算機類別**,不能直接使用,必須要先 **實體化(Instance)** 成**物件**才能使用。 ## 類別建立物件 通常從類別建立成物件,語法可以類似以下: ```csharp= // 類別名稱 物件名稱 = new 類別名稱(); // 例如: Calculate calculate = new Calculate(); // 依據類別Calculate建立一個物件calculate(注意大小寫) ``` 將類別建立成物件之後,你就可以把這個物件拿來使用。假設我們有一個機車類別: ```csharp= // 依據機車類別建立一個物件「我的機車」,物件名稱你可以自己設定,只要符合變數命名規範即可 機車類別 我的機車 = new 機車類別(); 我的機車.油箱 = 10; // 加滿油箱 我的機車.鑰匙插孔 = true; // 插入車鑰匙 我的機車.油門(); // 機車加速 我的機車.剎車(); // 機車減速 ``` 從上面的範例來看,你就可以知道機車類別與物件的差別,物件要從類別產生,我們要操作機車,是操作機車物件。 因此如果是計算機類別,我們就可以這樣操作它的物件,假設我們要計算的是「10 + 20」: ```csharp= Calculate calculate = new Calculate(); // 依據類別Calculate建立一個物件calculate(注意大小寫) calculate.firstNumber = 10; // 輸入第一個數字存在屬性firstNumber calculate.secondNumber = 20; // 輸入第二個數字存在屬性secondNumber int results = calculate.add(); // 執行加法,然後把結果賦值在變數results calculate.Reset(); // 執行重新設定,將所有屬性都回復到預設值 ``` 你可以注意到,要做計算工作,就只要將數值輸入到屬性,然後選擇要用哪一種四則運算並且執行那個方法,計算完成之後,就可以執行重新設定的方法,將所有屬性都回復到預設值。 之後,我們可以修改原來計算機程式的內容。 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Calculator { /// <summary> /// MainWindow.xaml 的互動邏輯 /// </summary> public partial class MainWindow : Window { Calculate calculate = new Calculate(); // 建立計算機物件 int operators = -1; // 記錄選擇哪一種運算符號?0:加、1:減、2:乘、3:除、-1:重新設定 public MainWindow() { InitializeComponent(); } private void btnOne_Click(object sender, RoutedEventArgs e) { Add_Number("1"); } private void btnTwo_Click(object sender, RoutedEventArgs e) { Add_Number("2"); } private void btnThree_Click(object sender, RoutedEventArgs e) { Add_Number("3"); } private void btnFour_Click(object sender, RoutedEventArgs e) { Add_Number("4"); } private void btnFive_Click(object sender, RoutedEventArgs e) { Add_Number("5"); } private void btnSix_Click(object sender, RoutedEventArgs e) { Add_Number("6"); } private void btnSeven_Click(object sender, RoutedEventArgs e) { Add_Number("7"); } private void btnEight_Click(object sender, RoutedEventArgs e) { Add_Number("8"); } private void btnNine_Click(object sender, RoutedEventArgs e) { Add_Number("9"); } private void btnZero_Click(object sender, RoutedEventArgs e) { Add_Number("0"); } // 按下數字按鍵函式 private void Add_Number(string _number) { if (txtNumber.Text == "0") txtNumber.Text = ""; txtNumber.Text = txtNumber.Text + _number; } private void btnAdd_Click(object sender, RoutedEventArgs e) { Select_Operator(0); } private void btnMinus_Click(object sender, RoutedEventArgs e) { Select_Operator(1); } private void btnPlus_Click(object sender, RoutedEventArgs e) { Select_Operator(2); } private void btnDivide_Click(object sender, RoutedEventArgs e) { Select_Operator(3); } // 運算符號按鍵函式 private void Select_Operator(int _operator) { calculate.firstNumber = Convert.ToSingle(txtNumber.Text); //將輸入文字框轉換成浮點數,再將數字存到計算機物件的firstNumber屬性裡面 operators = _operator; txtNumber.Text = "0"; //重新將輸入文字框重新設定為0 } private void btnDot_Click(object sender, RoutedEventArgs e) { // 確認輸入文字框中完全沒有小數點 if (txtNumber.Text.IndexOf(".") == -1) txtNumber.Text = txtNumber.Text + "."; } private void btnClear_Click(object sender, RoutedEventArgs e) { txtNumber.Text = "0"; calculate.Reset(); } private void btnEqual_Click(object sender, RoutedEventArgs e) { float finalResults = 0f; //宣告最後計算結果變數 calculate.secondNumber = Convert.ToSingle(txtNumber.Text); //將輸入文字框轉換成浮點數,再將數字存到計算機物件的secondNumber屬性裡面 //依照四則運算符號的選擇,進行加減乘除 switch (operators) { case 0: finalResults = calculate.Add(); // 執行加法 break; case 1: finalResults = calculate.Subtract(); // 執行減法 break; case 2: finalResults = calculate.Multiply(); // 執行乘法 break; case 3: finalResults = calculate.Divide(); // 執行除法 break; } txtNumber.Text = string.Format("{0:0.##########}", finalResults); //在輸入文字框中,顯示最後計算結果,並且轉換成格式化的字串內容 //重新設定計算機物件 calculate.Reset(); } } } ``` ## 結語 這裡介紹基本類別與物件的概念,其實它還有更多的細節與用途,同學日後還有很多機會學習物件導向的概念,但是最基本的就是類別與物件,先從最簡單的範例學起,以後你就可以慢慢入門。 以下也有幾篇網路上不錯的教學說明,建議你有機會可以多加練習與學習。 * [物件導向基礎:何謂類別(Class)?何謂物件(Object)?](https://blog.miniasp.com/post/2009/08/27/OOP-Basis-What-is-class-and-object) * [C#學習筆記 — 物件與類別(2)](https://blog.build-school.com/2022/05/13/c%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-%E7%89%A9%E4%BB%B6%E8%88%87%E9%A1%9E%E5%88%A52/) {%youtube E8zO_Djb1-c %}