前幾天我們已經學會:
現在已經可以寫出一些完整的程式邏輯。
例如計算一筆 Order:
decimal price = 250.5m;
int quantity = 5;
decimal total = price * quantity;
Console.WriteLine($"Total: {total}");
結果:
Total: 1252.5
但如果很多地方都需要計算總金額:
decimal total1 = price1 * quantity1;
decimal total2 = price2 * quantity2;
decimal total3 = price3 * quantity3;
相同的邏輯就會一直重複。
這時可以把「計算總金額」整理成一個:
Method(方法)
Method 可以把一段有明確功能的程式邏輯整理起來,需要時再重複使用。
今天會學到:
void
把原本的計算:
decimal total = price * quantity;
整理成 Method:
decimal CalculateTotal(decimal price, int quantity)
{
return price * quantity;
}
需要計算時:
decimal total = CalculateTotal(250.5m, 5);
Console.WriteLine(total);
結果:
1252.5
可以理解成:
資料傳入
↓
CalculateTotal()
↓
執行計算
↓
結果回傳
也就是:
資料進來
↓
Method
↓
處理資料
↓
結果出去
這就是今天最重要的基本模型。
先看完整程式:
decimal CalculateTotal(decimal price, int quantity)
{
return price * quantity;
}
呼叫:
decimal total = CalculateTotal(250.5m, 5);
第一次看到可能覺得有很多東西。
我們拆開來看:
decimal
→ Return Type
CalculateTotal
→ Method Name
decimal price, int quantity
→ Parameters
{
return price * quantity;
}
→ Method Body
可以先整理成:
Return Type
+
Method Name
+
Parameters
↓
Method Body
假設我們這樣寫:
decimal CalculateTotal()
{
return 250.5m * 5;
}
這個功能永遠只能計算:
250.5 × 5
沒有辦法處理其他 Order。
因此要讓外部資料可以傳進來。
這就是:
Parameter(參數)
例如:
decimal CalculateTotal(
decimal price,
int quantity)
{
return price * quantity;
}
這裡:
decimal price
int quantity
就是 Parameters。
它們定義:
這個 Method 執行時需要哪些資料。
所以現在可以處理不同的資料:
CalculateTotal(100m, 2);
CalculateTotal(250.5m, 5);
CalculateTotal(500m, 10);
當我們呼叫:
CalculateTotal(250.5m, 5);
這裡的:
250.5m
5
就是:
Argument(引數)
Parameter 與 Argument 很容易搞混。
可以這樣記:
宣告 Method
decimal price, int quantity
↓
Parameters
定義需要什麼
呼叫 Method
CalculateTotal(250.5m, 5)
↓
Arguments
實際傳入什麼
一句話:
Parameter 定義需要什麼,Argument 是呼叫時實際傳入的資料。
資料已經可以透過 Parameter 傳進 Method。
下一個問題是:
處理完成的結果,要怎麼傳回來?
這就是:
return
的用途。
例如:
decimal CalculateTotal(
decimal price,
int quantity)
{
return price * quantity;
}
呼叫:
decimal total = CalculateTotal(250.5m, 5);
執行流程:
CalculateTotal(250.5m, 5)
↓
price = 250.5m
quantity = 5
↓
price * quantity
↓
return 1252.5m
↓
total = 1252.5m
這裡有兩個重要名詞:
Return Type
Return Value
看這段:
decimal CalculateTotal(
decimal price,
int quantity)
最前面的:
decimal
就是:
Return Type(回傳型別)
代表:
這個 Method 最後會回傳一個
decimal。
例如:
bool IsValidOrder(...)
代表回傳:
bool
而:
string GetStatus(...)
代表回傳:
string
Method 裡:
return price * quantity;
實際執行後傳回去的資料,就是:
Return Value(回傳值)
例如:
Return Type
→ decimal
Return Value
→ 1252.5m
所以:
Return Type 規定回傳什麼 Type,Return Value 是實際回傳的資料。
void不是所有 Method 都需要回傳資料。
例如只是輸出 Order:
void PrintOrder(string product)
{
Console.WriteLine($"Product: {product}");
}
它只負責:
輸出資料
沒有需要把結果傳回來。
因此使用:
void
可以先這樣區分:
CalculateTotal()
→ 需要計算結果
→ decimal + return
IsValidOrder()
→ 需要判斷結果
→ bool + return
PrintOrder()
→ 只負責輸出
→ void
簡單記:
需要回傳結果
→ Return Type + return
不需要回傳結果
→ void
Method 不只能計算。
也可以把條件判斷整理成有意義的功能。
例如原本:
if (price <= 0 || quantity <= 0)
{
Console.WriteLine("Invalid Order");
}
可以把「Order 是否有效」整理成:
bool IsValidOrder(
decimal price,
int quantity)
{
return price > 0 && quantity > 0;
}
呼叫:
bool isValid = IsValidOrder(100m, 5);
甚至可以直接:
if (IsValidOrder(100m, 5))
{
Console.WriteLine("Order Accepted");
}
看到:
IsValidOrder(...)
就可以直接理解:
判斷 Order 是否有效
這也是 Method Name 很重要的原因。
return 也可以提前結束 Methodreturn 除了可以回傳資料,也可以直接結束目前的 Method。
例如:
void PrintOrder(
decimal price,
int quantity)
{
if (price <= 0 || quantity <= 0)
{
Console.WriteLine("Invalid Order");
return;
}
Console.WriteLine("Order Accepted");
}
如果 Order 不合法:
return;
Method 就會立即結束。
後面的:
Console.WriteLine("Order Accepted");
不會再執行。
這種寫法常稱為:
Early Return(提前回傳)
可以理解成:
條件不符合
↓
return
↓
提前結束
它可以減少過多的 if / else 巢狀結構,讓主要流程更容易閱讀。
Method 裡面的 Variable 有自己的:
Scope(作用域)
例如:
decimal CalculateTotal(
decimal price,
int quantity)
{
decimal total = price * quantity;
return total;
}
這裡的:
price
quantity
total
只能在它們所在的 Scope 中使用。
例如 Method 外面不能直接:
Console.WriteLine(total);
存取 Method 裡宣告的 total。
目前先簡單理解:
Scope 就是 Variable 可以被存取與使用的範圍。
Method 的價值不只是:
避免 Copy / Paste
更重要的是:
把不同責任拆開。
例如一筆 Order 有三件事情:
驗證 Order
計算 Total
輸出 Order
可以分成:
bool IsValidOrder(
decimal price,
int quantity)
{
return price > 0 && quantity > 0;
}
decimal CalculateTotal(
decimal price,
int quantity)
{
return price * quantity;
}
void PrintOrder(
string product,
decimal total)
{
Console.WriteLine(
$"Product: {product}, Total: {total}"
);
}
每個 Method 都有清楚的責任:
IsValidOrder()
→ 驗證
CalculateTotal()
→ 計算
PrintOrder()
→ 輸出
初期可以先記住:
一個 Method 專注處理一件清楚的事情。
不需要刻意拆得越小越好。
真正重要的是:
名稱清楚
責任清楚
容易閱讀
Method Name 應該清楚表達它正在做什麼。
例如:
CalculateTotal()
IsValidOrder()
PrintOrder()
GetPrice()
常見命名方式:
| 命名 | 常見用途 |
|---|---|
Calculate... |
計算 |
Get... |
取得資料 |
Print... |
輸出 |
Validate... |
驗證 |
Is... |
判斷是否符合條件 |
例如:
bool IsValidOrder(...)
從名稱與 Return Type 就能大概理解:
IsValidOrder
→ 判斷 Order 是否有效
bool
→ 回傳 true / false
Method Name 本身就是程式可讀性的一部分。
最後把前面的概念組合起來。
string product = "TXF";
decimal price = 250.5m;
int quantity = 5;
if (IsValidOrder(price, quantity))
{
decimal total = CalculateTotal(price, quantity);
PrintOrder(product, total);
}
else
{
Console.WriteLine("Invalid Order");
}
bool IsValidOrder(
decimal price,
int quantity)
{
return price > 0 && quantity > 0;
}
decimal CalculateTotal(
decimal price,
int quantity)
{
return price * quantity;
}
void PrintOrder(
string product,
decimal total)
{
Console.WriteLine(
$"Product: {product}, Total: {total}"
);
}
結果:
Product: TXF, Total: 1252.5
現在主程式可以直接讀成:
準備 Order 資料
↓
IsValidOrder()
↓
驗證 Order
↓
CalculateTotal()
↓
計算 Total
↓
PrintOrder()
↓
輸出結果
就算先不看每個 Method 裡面的實作,也能理解程式大概在做什麼。
這就是 Method 很重要的價值:
把程式拆成有名稱、有責任、可以重複使用的功能。
今天我們解決的問題是:
一段程式邏輯,要怎麼整理成可以重複使用的功能?
答案就是:
Method
Parameter
→ 定義 Method 需要什麼資料
Argument
→ 呼叫 Method 時實際傳入的資料
例如:
CalculateTotal(100m, 3);
price、quantity
→ Parameters
100m、3
→ Arguments
Return Type
→ 規定回傳什麼 Type
Return Value
→ 實際回傳的資料
需要回傳結果:
Return Type + return
不需要回傳結果:
void