屬性的get & 建構函式 的使用時機(以Winforms計算機小程式為例)

大家一定都想知道,真正以寫程式開發為職業的人,他們在寫程式時思考的方向是什麼?

以編寫計算機程式為例,他們會希望不讓用戶看到:
為了讓編譯器(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!