大家一定都想知道,真正以寫程式開發為職業的人,他們在寫程式時思考的方向是什麼?
以編寫計算機程式為例,他們會希望不讓用戶看到:
為了讓編譯器(compiler)運算而對資料型別的轉換,而是更直覺地提供用戶更方便的使用體驗。
我們可以試想,當在使用一台計算機時,我們是不是只管輸入數字,然後就會得到一個數字答案,
我們不會管內部是如何運作而得出答案的!
其實這種隱藏內部複雜運算的想法&考慮到用戶體驗感受,兩者是有關聯的!
身為程式的初學者,我嘗試著將用戶歸類為跟我一起開發程式的夥伴,我必須考量這些夥伴在測試我的程式以及在為了下一階段的開發,能不能快速地理解我的程式碼?
為什麼只是通過編寫一個小程式,就能讓我有這種體悟呢?
我們都知道當我們想要讓程式實現更多功能時,我們所編寫的程式碼長度就愈長,也更不好維護,
所以大部分寫程式的人都知道,我們要試著使用不同的函式將相關的程式碼組織起來、歸類在一起,而不是將所有程式碼都放在主函式。
現在我們回到計算機這個小程式,對於用戶來說,如果在他們使用計算機前還必須了解資料型別的轉換,那是不是很不方便呢?
而對於我的開發夥伴來說,若我不懂得使用其他函式來組織在做同一件事的程式碼,他們就會直接地看到我在主函式編寫一來一回的資料型別轉換,
雖然說使用功能不影響,但是程式碼讀起來就無法達到言簡意賅了!
最近我學到一個可以將屬性(Property)的get當作函式來使用的方式,它可以用來編寫較短的運算邏輯語句。
當我嘗試把資料型別轉換 & +-*/運算使用屬性(Property)組織起來,在我需要使用時,我可以重複叫用(Invoke),然而在主函式的部分,就不用編寫重複的程式碼囉!
以下是我在網路上找到的:使用函式的益處
函式 (function) 是程序抽象化 (procedure abstraction) 的實踐方式,使用函式有以下的好處:
- 減少撰寫重覆的程式碼
- 將程式碼以有意義的方式組織起來
- 在相同的流程下,可藉由參數調整程式的行為
- 藉由函式庫可組織和分享程式碼
- 做為資料結構 (data structures) 和物件 (objects) 的基礎
資料出自:https://michaelchen.tech/c-programming/function/
接著,編寫一個程式除了考慮使用的方便性之外,也必須避免Exception的發生。
若你在開發一個軟體給用戶,要常常考慮到,如何避免用戶使用時報錯情況的發生;同樣的想法也可用在開發夥伴上。
例如用戶要使用計算機來運算前,都必須提供兩個數字與一個算數運算符,那麼這3個部份就變成必要的資訊,
所以可以寫成帶參數的建構函式(Constructor,有時簡稱ctor),來限制用戶在使用之前,必須先提供這些資訊。
(這個與帶參數的方法有異曲同工之妙,但方法通常都是用來寫較複雜的邏輯表達,若想表達的邏輯語句比較短,則可以使用建構函式)。
好了,已經說了這麼多抽象的概念,直接來看程式碼比對這些觀念,相信會更容易理解。
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
string number1 = "";
string number2 = "";
string operation = "";
public Form1()
{
InitializeComponent();
}
private void Nums_Clicked(object sender, EventArgs e)
{
if (result.Text=="0")
result.Text = "";
Button button = (Button)sender;
result.Text += button.Text;
}
private void Operators_Clicked(object sender, EventArgs e)
{
number1 = result.Text;//必要的第一個數字
result.Text = "";
Button button = (Button)sender;
operation = button.Text;//必要的算術運算子
}
private void Equal_Clicked(object sender, EventArgs e)
{
number2 = result.Text;//必要的第二個數字
Calculator calculator = new Calculator(number1,number2,operation);//在這裡用戶必須傳入必要的參數
result.Text = calculator.Result;
}
private void Clear_Clicked(object sender, EventArgs e)
{
result.Text = "";
}
}
}
在同一個專案下新增一個自訂型別Calculator
namespace WindowsFormsApp2
{
class Calculator
{
private int num1 { get; set; }
private int num2 { get; set; }
private string oper { get; set; }
public Calculator(string number1,string number2, string operation)//用ctor強制用戶傳入必要資訊
{
this.num1 = int.Parse(number1);//將型別轉換藏在這裡
this.num2 = int.Parse(number2);
this.oper = operation;
}
private string _result;
public string Result
{
get
{//把get當作方法來用(將型別轉換與加減乘除運算藏在這裡),也能避免運算邏輯遭到修改
switch (oper)
{
case "+":
_result = (num1 + num2).ToString();//將型別轉換藏在這裡
break;
case "-":
_result = (num1 - num2).ToString();
break;
case "*":
_result = (num1 * num2).ToString();
break;
case "/":
_result = (num1 / num2).ToString();
break;
default:
break;
}
return _result;
}
}
}
}
最後,來分享寫這個程式,拆解成子問題的步驟:
當你按下第一個數字按鈕......個數字按鈕 →直到你再按下算術運算子+-*/後呢 →才得到真正的第一個數字
(你可以將此算術運算子+-*/的Text存儲下來以做後面的判斷:用switch-case)
當你按下第一個數字按鈕......個數字按鈕 →直到你再按下算術運算子=後呢 →才得到真正的第二個數字
(當你按下=之後要做什麼事呢) →將得到的3個必要資訊結合在這裡做計算
當你照著這個邏輯步驟,相信你已經寫出正常功能的計算機了,但是這時所有程式碼都在主函式裡;那麼接下來要開始想,如何使用Constructor與Property的get來組織程式碼。
(既然你得到的所有資訊都是string類型,那要如何計算呢?)要如何將型別轉換隱藏起來呢?→如何才能讓轉型與運算都不在主函式裡呢?
以上是我對於此程式的小小心得,希望在編寫程式上有幫助到大家!
註:這個計算機做出來長這樣…
知識補充:優化此程式碼
假設說今天我們使用這台計算機時,我們可以讓用戶取得(唯讀)當初輸入的兩個數字。
雖然說計算機的基本功能只是得到運算的結果,但是我們可以試想,當用戶看到運算結果時,可能早已忘記剛才輸入什麼值了,這時我們可以透過優化程式碼來解決,只要秉持著對內操作欄位(field)、對外可叫用唯讀屬性(只有get),我們就可以實現這個想法了!
針對Calculator型別,新增Num1、Num2唯讀屬性,兩者對外都可被叫用,只讀不寫。
public string Num1 { get {
return this.num1.ToString();
} }
public string Num2 { get {
return this.num2.ToString();
} }
多寫了這兩個唯讀屬性到Calculator class裡,我們就可以在主函式輸出Num1,Num2的值了,也就是外部能夠取得值、但是不能設定值。
我們能在這句程式碼後面:Calculator calculator = new Calculator(number1,number2,operation);
叫用唯讀屬性Num1,Num2,程式碼如下:
Console.WriteLine(calculator.Num1);
Console.WriteLine(calculator.Num2);
結論是,以這個程式來看,我們對外是能夠取得Num1,Num2與Result的,但是不能設定!
那麼,下篇見!
如有敘述錯誤,還請不吝嗇留言指教,thanks!