iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Modern Web

現在就學C# 與 ASP.NET Core系列 第 10 篇

Day 10|Class 與 Object:把相關資料與行為組織在一起

  • 分享至 

  • xImage
  •  

Day 9 我們學會使用 Method(方法),把一段程式邏輯整理成可以重複使用的功能。

例如:

decimal CalculateTotal(
    decimal price,
    int quantity)
{
    return price * quantity;
}

但是目前一筆 Order 的資料仍然是分開的:

string product = "TXF";
decimal price = 250.5m;
int quantity = 5;

實際上:

product
price
quantity

都在描述同一件事情:

一筆 Order。

如果資料越來越多:

string product = "TXF";
decimal price = 250.5m;
int quantity = 5;
string side = "Buy";
string status = "Pending";

Variable 也會越來越零散。

因此今天要解決的問題是:

如何把屬於同一個概念的資料與功能組織在一起?

這就是:

Class(類別)


今天會提到

  • Class
  • Field
  • Object
  • Instance
  • new
  • Constructor
  • Instance Method

Class的運作關係可以這樣看:

Class
→ 定義一種 Type
        ↓
       new
        ↓
Object / Instance
→ 實際建立出來的物件

1. 為什麼需要 Class?

目前一筆 Order:

string product = "TXF";
decimal price = 250.5m;
int quantity = 5;

程式看到的是三個獨立的 Variable:

product
price
quantity

但我們真正想表達的是:

Order
├── Product
├── Price
└── Quantity

也就是:

這些資料其實都屬於同一筆 Order。

因此可以建立:

class Order
{
    public string Product = "";
    public decimal Price;
    public int Quantity;
}

現在:

Product
Price
Quantity

不再只是三個零散的資料,而是共同屬於:

Order

所以 Class 第一個重要用途就是:

把屬於同一個概念的資料與行為組織在一起。


2. Class:自己定義一種新的 Type

前面我們使用過:

int quantity = 5;
decimal price = 250.5m;
string product = "TXF";

其中:

int
decimal
string

都是 Type(型別)。

例如:

int quantity;

可以拆成:

int
→ Type

quantity
→ Variable

現在我們建立:

class Order
{
}

代表:

我們自己定義了一種新的 Type:Order。

因此也可以寫:

Order order;

拆開來看:

Order
→ Type

order
→ Variable

可以這樣比較:

int
→ C# 已經提供的 Type

Order
→ 我們透過 Class 自己定義的 Type

所以 Class 不只是把程式碼包起來。

更重要的是:

Class 可以讓我們定義自己的 Type。


3. Field:描述 Object 有哪些資料

回到:

class Order
{
    public string Product = "";
    public decimal Price;
    public int Quantity;
}

其中:

Product
Price
Quantity

稱為:

Field(欄位)

可以理解成:

Order
│
├── Product  → string
├── Price    → decimal
└── Quantity → int

Field 用來保存 Object 的資料。

所以:

Field 描述這類 Object 需要保存哪些資料。


public 是什麼?

目前 Field 前面都有:

public

今天先簡單理解成:

Class 外部可以存取這個成員。

例如之後可以寫:

order.Price

今天暫時使用 public Field,目的是先專心理解 Class 與 Object。

實務上通常不會直接把所有 Field 公開。

下一篇介紹 Property 與 Encapsulation 時,再正式處理這個問題。


4. 使用 new 建立 Object

目前:

class Order
{
    public string Product = "";
    public decimal Price;
    public int Quantity;
}

只是定義:

Order 這種 Type

還沒有真正建立任何一筆 Order。

要建立實際的 Object,可以使用:

Order order = new Order();

這行可以拆成:

Order
→ Type

order
→ Variable

new Order()
→ 建立新的 Order Object

整個流程:

Order Class
     ↓
 new Order()
     ↓
Order Object
     ↓
   order

所以先記住:

Class 負責定義,new 負責建立 Object。


5. 建立與使用 Object

建立 Object:

Order order = new Order();

接著可以設定這筆 Order 的資料:

order.Product = "TXF";
order.Price = 250.5m;
order.Quantity = 5;

現在 order 可以理解成:

order
│
├── Product  = "TXF"
├── Price    = 250.5
└── Quantity = 5

以前我們使用:

string product = "TXF";
decimal price = 250.5m;
int quantity = 5;

現在則變成:

order.Product
order.Price
order.Quantity

從程式碼就可以直接看出:

這些資料都屬於同一筆 Order。


.:存取 Object 的成員

例如:

order.Price

中間的:

.

稱為:

Member Access Operator(成員存取運算子)

目前可以簡單理解:

order.Price

order
→ 哪一個 Object

Price
→ 使用這個 Object 的哪個成員

例如:

order.Product
order.Price
order.Quantity

之後也會看到:

order.CalculateTotal();

都是透過 . 存取 Object 的成員。


6. Class、Object 與 Instance

到這裡需要先分清楚兩個最重要的概念:

Class
→ 定義

Object
→ 根據 Class 實際建立出來的物件

例如:

class Order
{
    public string Product = "";
    public decimal Price;
    public int Quantity;
}

這是在定義:

Order 這種 Type

而:

Order order = new Order();

才真正建立出:

Order Object

根據某個 Class 建立出來的 Object,也常稱為這個 Class 的:

Instance(執行個體)

因此:

new Order()

可以理解成:

建立一個 Order Object,也就是建立一個 Order Instance。

目前先記成:

Class
→ 定義

      ↓ new

Object / Instance
→ 實際建立出來的物件

初學階段不用特別糾結 Object 與 Instance 的差異,把它們先視為非常接近的概念即可。


7. 為什麼需要 Constructor?

目前建立一筆 Order,需要先:

Order order = new Order();

再逐一設定:

order.Product = "TXF";
order.Price = 250.5m;
order.Quantity = 5;

雖然可以正常使用,但有一個問題。

我們可能只寫:

Order order = new Order();

然後忘記設定資料。

如果希望:

建立 Order 的同時,就把需要的資料準備好。

可以使用:

Constructor(建構函式)


8. Constructor:建立 Object 時完成初始化

把 Order 改成:

class Order
{
    public string Product;
    public decimal Price;
    public int Quantity;

    public Order(
        string product,
        decimal price,
        int quantity)
    {
        Product = product;
        Price = price;
        Quantity = quantity;
    }
}

現在建立 Object 時,可以直接提供資料:

Order order =
    new Order("TXF", 250.5m, 5);

建立完成後:

order
│
├── Product  = "TXF"
├── Price    = 250.5
└── Quantity = 5

因此 Constructor 可以先理解成:

Constructor 會在建立 Object 時執行,用來初始化 Object 的資料。


看懂 Constructor

回頭看:

public Order(
    string product,
    decimal price,
    int quantity)
{
    Product = product;
    Price = price;
    Quantity = quantity;
}

可以拆成:

public
→ Access Modifier

Order
→ Constructor Name

string product
decimal price
int quantity
→ Parameters

{ ... }
→ Constructor Body

Constructor 有兩個重要特徵。

第一:

Constructor Name
→ 和 Class Name 相同

例如:

class Order

對應:

public Order(...)

第二:

Constructor
→ 沒有 Return Type

所以是:

public Order(...)

不是:

public void Order(...)

Constructor 也有 Parameter 與 Argument

Day 9 學過:

Parameter
→ 定義需要什麼資料

Argument
→ 呼叫時實際傳入什麼資料

Constructor 也是一樣。

宣告:

public Order(
    string product,
    decimal price,
    int quantity)

其中:

product
price
quantity

是 Parameters。

建立 Object:

new Order("TXF", 250.5m, 5);

其中:

"TXF"
250.5m
5

是 Arguments。

整個流程:

"TXF", 250.5m, 5
      Arguments
          ↓
product, price, quantity
      Parameters
          ↓
    Constructor
          ↓
    初始化 Object
          ↓
Product = "TXF"
Price = 250.5
Quantity = 5

可以看到 Day 9 的 Parameter / Argument 概念,在 Constructor 這裡仍然可以繼續使用。


9. Class 也可以定義行為

Class 不只能保存資料。

還可以定義:

Behavior(行為)

例如 Day 9 的:

decimal CalculateTotal(
    decimal price,
    int quantity)
{
    return price * quantity;
}

這個功能本來就在處理 Order。

而:

Price
Quantity

本來就是 Order 自己的資料。

因此可以把 CalculateTotal() 放進 Order:

class Order
{
    public string Product;
    public decimal Price;
    public int Quantity;

    public Order(
        string product,
        decimal price,
        int quantity)
    {
        Product = product;
        Price = price;
        Quantity = quantity;
    }

    public decimal CalculateTotal()
    {
        return Price * Quantity;
    }
}

現在 Order 同時具有:

Order
│
├── Data
│   ├── Product
│   ├── Price
│   └── Quantity
│
└── Behavior
    └── CalculateTotal()

所以 Class 更完整的概念就是:

把屬於同一個概念的資料,以及操作這些資料的行為組織在一起。


10. Instance Method:Object 使用自己的資料

現在建立:

Order order =
    new Order("TXF", 250.5m, 5);

可以直接:

decimal total =
    order.CalculateTotal();

結果:

1252.5

Day 9 原本需要:

CalculateTotal(price, quantity);

現在只需要:

order.CalculateTotal();

為什麼?

因為:

order 自己已經擁有 Price 與 Quantity。

可以理解成:

order
│
├── Price = 250.5
├── Quantity = 5
│
└── CalculateTotal()
        ↓
   Price × Quantity

這種屬於 Object,並且可以使用這個 Object 自己資料的 Method,稱為:

Instance Method(執行個體方法)

這是從 Day 9 到 Day 10 很重要的一個變化:

以前

資料
 ↓
傳進 Method

現在

Object
├── 自己的資料
└── 操作自己資料的 Method

再加入 Order 驗證

Day 9 原本寫:

bool IsValidOrder(
    decimal price,
    int quantity)
{
    return price > 0 &&
           quantity > 0;
}

但是:

Price
Quantity

同樣都是 Order 自己的資料。

因此也可以把驗證放進 Order:

public bool IsValid()
{
    return Price > 0 &&
           Quantity > 0;
}

現在可以:

if (order.IsValid())
{
    Console.WriteLine(
        order.CalculateTotal()
    );
}

這時 Order 已經同時具有:

Order
│
├── Data
│   ├── Product
│   ├── Price
│   └── Quantity
│
└── Behavior
    ├── IsValid()
    └── CalculateTotal()

也就是:

Object 不只保存自己的資料,也可以擁有操作這些資料的行為。


11. 完整的 Order Class

現在把今天學到的內容組合起來:

class Order
{
    public string Product;
    public decimal Price;
    public int Quantity;

    public Order(
        string product,
        decimal price,
        int quantity)
    {
        Product = product;
        Price = price;
        Quantity = quantity;
    }

    public bool IsValid()
    {
        return Price > 0 &&
               Quantity > 0;
    }

    public decimal CalculateTotal()
    {
        return Price * Quantity;
    }
}

整個 Class 可以拆成:

Order Class
│
├── Fields
│   ├── Product
│   ├── Price
│   └── Quantity
│
├── Constructor
│   └── Order(...)
│
└── Instance Methods
    ├── IsValid()
    └── CalculateTotal()

也就是:

Class
│
├── 定義資料
│
├── 定義初始化方式
│
└── 定義行為

這就是今天最重要的 Class 心智模型。


12. 使用 Order Class

建立一筆 Order:

Order order =
    new Order("TXF", 250.5m, 5);

接著使用它:

if (order.IsValid())
{
    decimal total =
        order.CalculateTotal();

    Console.WriteLine(
        $"Product: {order.Product}, Total: {total}"
    );
}
else
{
    Console.WriteLine("Invalid Order");
}

結果:

Product: TXF, Total: 1252.5

整個流程:

Order Class
     ↓
new Order(...)
     ↓
Constructor
     ↓
初始化 Object
     ↓
   order
     ↓
IsValid()
     ↓
CalculateTotal()
     ↓
輸出結果

從這裡開始,程式不再只是:

零散的 Variable
+
零散的 Method

而是:

Order Object
│
├── 自己的資料
└── 自己的行為

13. 一個 Class 可以建立很多 Object

Class 只需要定義一次:

class Order
{
    // ...
}

但可以建立很多不同的 Object:

Order order1 =
    new Order("TXF", 250.5m, 5);

Order order2 =
    new Order("MXF", 120m, 10);

可以理解成:

          Order Class
              │
       ┌──────┴──────┐
       ↓             ↓
    order1         order2
       │             │
      TXF           MXF

所以:

Class 只需要定義一次,但可以建立很多 Object,每個 Object 都保存自己的資料。


14. Class 要放在哪裡?

目前我們使用的是 Top-level Statements。

如果暫時都寫在同一個 Program.cs,可以像這樣:

Order order =
    new Order("TXF", 250.5m, 5);

Console.WriteLine(
    order.CalculateTotal()
);

// Class 放在 Top-level Statements 後面
class Order
{
    // ...
}

也可以另外建立:

Order.cs

專門放:

class Order
{
    // ...
}

初學階段兩種方式都可以。

當 Class 開始變大時,拆成獨立的 .cs 檔案通常會更容易整理。


Day 10 小結

今天我們解決的問題是:

如何把屬於同一個概念的資料與功能組織在一起?

答案就是:Class

Class

class Order
{
    // ...
}

用來定義一種新的 Type,描述這類 Object 有哪些資料與行為。


Field

例如:

public decimal Price;

用來保存 Object 的資料。


Object / Instance

例如:

Order order =
    new Order("TXF", 250.5m, 5);

其中:

Order
→ Type

order
→ Variable

new
→ 建立 Object

new Order(...)
→ 建立一個 Order Object / Instance

Constructor

例如:

public Order(
    string product,
    decimal price,
    int quantity)

會在建立 Object 時執行,用來初始化資料。


Instance Method

例如:

order.CalculateTotal();

Instance Method 可以直接使用這個 Object 自己的資料。

整篇可以整理成:

原本:

Product
Price
Quantity

都是零散 Variable
        ↓
       Class
        ↓
定義新的 Type
        ↓
      Field
描述有哪些資料
        ↓
       new
        ↓
Object / Instance
        ↓
  Constructor
初始化 Object
        ↓
Instance Method
使用 Object 自己的資料

上一篇
Day 9|Method:把程式邏輯整理成可以重複使用的功能
下一篇
Day 11|Encapsulation 與 Property:讓 Class 管理自己的資料
系列文
現在就學C# 與 ASP.NET Core 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言