---
tags: 視窗程式設計
---
# 類別與物件的觀念
如果你開始感受到函式的好用,可以大幅度減少高度類似的程式碼,還能進一步讓程式更精簡,接下來你就可以進一步了解「類別與物件」。
首先,我們幫同學建立「類別」的概念,當你開始學習類別,你就開始入門 **物件導向程式設計(Object-Oriented Programming, OOP)** 了。
:::success
**恭喜你,開始脫離程式新手村。**
:::
第一次聽到類別這個東西,你一定覺得很難理解這是甚麼?沒關係,我們慢慢來,先從日常的範例想像一下:
## 假設你要騎一台機車
如果你要騎一台機車出門兜風,那要怎麼做呢?
:::info
交通安全宣導:請同學務必考取駕照後再上路。
:::
1. 你需要先幫機車加足夠的汽油
2. 跨上車,將鑰匙插入鑰匙孔,啟動引擎
3. 轉油門手把,機車就會加速往前跑
4. 如果速度太快,要放鬆油門手把,適度拉剎車手把
**以上應該你都可以理解吧?** 如果可以理解的話,你應該可以理解所謂類別的觀念。
:::info
「類別(Class)」是將生活中事物「抽象化」,或者我們將抽象化改稱為「簡化」也可以。
:::
現在我們將一台機車的功能與狀態「簡化」一下,請參考下圖:

因此一個機車的「類別」,你可以看成就是機車的簡化概念,其中類別可以分成「**屬性(Property)**」與「**方法(Method)**」。
* 屬性:定義類別的特性
* 方法:定義類別可操作的工作
用比較簡單的方式來解釋屬性與方法。
:::info
1. 你需要先幫機車加足夠的汽油:**設定油箱屬性**
2. 跨上車,將鑰匙插入鑰匙孔,啟動引擎:**設定鑰匙插孔屬性**
4. 轉油門手把,機車就會加速往前跑:**執行油門方法**
5. 如果速度太快,要放鬆油門手把,適度拉剎車手把:**執行剎車方法**
:::
因此類別就是一種將日常事物「抽象化」或「簡化」的方式,你或許不太習慣,以後可以多練習,把生活中的事物也用類似的方式簡化,就會慢慢習慣類別的概念。
## 寫一個程式的類別
了解基本的類別概念之後,我們就直接實作,這樣更能加深你的印象。
我們繼續使用之前的**計算機程式**,將它原本計算機進行計算邏輯的部分獨立出來,變成類別,這樣更能將程式變得更有結構。因此請開啟上一章節完成的計算機程式專案,我們繼續用這個專案當範例。
首先我們跟同學介紹如何在 Visual Studio 新增一個類別的程式檔,通常它可以放在一般程式碼裡面或者獨立一個檔案,這邊我們介紹如何將類別寫成獨立檔案。
:::info
寫成獨立檔案的好處就是,你可以直接在把這個檔案複製到另一個專案檔裡面,很簡單的直接使用。
:::

看大圖:https://i.imgur.com/2O6qLTj.png
新增一個類別檔案的方式,請在方案總管中點選你的專案名稱上面按右滑鼠鍵,選擇加入 -> 新增項目。

看大圖:https://i.imgur.com/ePvLrnE.png
接著就會出現這個視窗,請確定有沒有選到類別的項目,然後名稱取名為「Calculate.cs」,名稱一樣不要用中文或違反命名規則,最後按新增的按鍵。

完成之後,你就會看到方案總管中有這個類別檔案了。對這個檔案點兩下開啟,再新增以下的程式碼。
```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),以類似機車類別的方式,整理成下表的形式。

你可以不要先看程式內容,先看這張表格,就可以大致了解這個計算機類別可以做甚麼?並且如果你還記得計算機程式的執行邏輯,其實也是這個類別可以完成的。
:::info
1. 輸入第一個數字:**將數字存在屬性firstNumber**
2. 輸入第二個數字:**將數字存在屬性secondNumber**
3. 按等於按鍵:**執行特定的四則運算方法**
4. 按AC按鍵:**執行重新設定方法**
:::
### 類別其實有點像是海軍命名船舶常用的「船級」名稱
例如第二次世界大戰美國的有名戰艦艦級「**愛荷華級(Iowa-class Battleship)**」,**愛荷華級代表的是某個型號的戰艦**,因此會有數艘同型的戰艦,歷史上愛荷華級的戰艦包括:愛荷華號、紐澤西號、密蘇里號、威斯康辛號(還有兩艘沒有完成的)。
「類別」就類似某種型號的戰艦,只要是同一型號的戰艦,都會有類似的型態,這些戰艦就是根據類別製造出來的「物件」,之後我們會把這個概念繼續在「物件」中進一步說明。

## 簡單的結論
類別的設計,你可以用一個整體的思考方式,來規劃程式的架構。
例如計算機程式,你可以將原來的程式邏輯,分別依照屬性與方法的概念做一個整理,再將這些程式整理成類別來使用。你可以更好的修改或調整程式,如果是其他的程式設計師也可以方便的用你寫好的類別。
甚至我們可以將屬性與方法的使用方式說清楚,別的程式設計師可以不需要深入了解你的程式內容,只要知道有甚麼屬性與方法?知道這些屬性與方法如何使用?他們就可以快速的將你的程式用在他們的專案。
:::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 %}