Views: 22
物件導向算是新手最常學到這邊就棄坑的部分,不過筆者認為是這樣,很多技能要實際使用一陣子才會有所認識,所以蠻多我都認為一開始學矇矇的沒關係,有一定的印象,多數時候先求看的懂程式就好。
跟大家說個好消息,基本上程式設計自從有函數function、物件導向Object-oriented後,就沒什麼畫時代大型變化,所以大概這關過了之後程式設計就打破最難的關卡。然後建議大家先別管書上有什麼複雜的抽象、泛型等等高級作法,我會從基本簡單的開始。
class (類別)
class(類別)與object(物件)是個不容易找到現實中類比,我認為比較接近的概念是建築設計圖。
- 程式設計師寫類別 → 建築師繪製設計圖。
- 程式執行時將類別實體化(Instance)為物件 → 營造廠照著設計圖把房子蓋出來。
Instance 實體化
電腦執行程式時,遇到要將物件實體化會進行下列動作
- 在記憶體找塊空間
- 把class內容放一份放到那塊空間
簡單的說,實體化就是把物件具現化(獵人漫畫的用詞),類似在地球上租塊地按照藍圖把房子蓋起來的概念。
object 物件
當房子蓋好後,就可以開始使用這間房子搬進去住了。
//假設有個class叫做Bank,instance(實體化)object(物件)命名為bank
Bank bank = new Bank();
工作時候華人工程師會說,把物件new出來,就是指將class這樣new成一個變數。
物件導向程式設計起步走
到這邊先開一個新專案,假設我們要來設計銀行存款系統。
開一個主控台專案
名字這邊我取SunnyBank 你可以照自己喜歡的取名。
設計存款帳號類別Account class
注意 程式語言的
class
要打小寫的
這邊我先解釋一下C#的程式碼
主要分為方案、專案,概念其實很簡單,一個方案下可以有很多個專案,然後如果是大型專案就會一個方案下有十幾個專案。
- OO系統方案
- 網站後台專案
- 網站前台WebApi專案
- 底層類別專案
- 共用函數專案
- 資料庫存取專案
- 系統排程專案
- 單元測試專案
這邊因為才新開,所以只會有一個方案跟一個專案
底下那個C# SundayBank就是專案,上面紫色圖示的是方案。
新增類別檔class
(1)在SundayBank專案按下右鍵→(2)加入(Add)→(3)類別
class1.cs
→ 名稱輸入Account.cs
,Account就是我們類別的命名,在C#的設計習慣類別名稱會使用大寫開頭為主,不過這點如果學員開始工作,就看各公司對程式的命名規定(但通常沒有)。
這邊我先解釋一下
//using 指的是參考了哪些類別(對..程式碼有很多內建的類別可以拿來用)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//namespace 用來區分這個class要放在那邊用的,我們先別管
namespace SundayBank
{
//internal 這是存取範圍,指這個class只能在專案內呼叫,不能被其他專案呼叫
//class 就是class
// Account → class的名稱
internal class Account
{
}
}
物件存取範圍
官方說明 協助工具層級 – C# reference | Microsoft Learn
官方列了七個範圍,新手先記最常用這兩個
public
不限制。private
最嚴格限制,只有class內可以存取。- 沒定義 = private
Property 屬性(欄位)
一個銀行帳號裡面有哪些重要資訊:
- 存戶名 →
Name
- 帳號號碼 →
Number
- 開戶時間 →
CreateTime
- 目前現金存款 →
Cash
- 存戶身分證字號 →
RocId
這些開戶表格上要跟著記在戶頭資料中的,就是所謂的屬性。接下來將屬性補上如下,這邊練習時先將存取範圍都訂為public。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
public class Account
{
public string Name{get;set;}
public string Number{get;set;}
public DateTime CreateTime{get;set;}
public decimal Cash{get;set;}
public string RocId{get;set;}
}
}
屬性命名習慣
官方文件 命名方針 – Framework Design Guidelines | Microsoft Learn
C# 普遍上public的屬性命名都會是字首大寫。如果命名是兩個單字則要改為兩個字首大寫。
好的範例:Number、Name
不好的範例:number、User_Name、USER。
屬性的註解
很多書都是教這樣寫註解,不過我個人非常的不推薦
//存戶名稱
public string Name { get; set;} //也有寫在後面的
欄位屬性有標準的註解方式,作法則是
在屬性上方輸入三個斜線,系統會自動長出標準的格式
/// <summary>
/// 存戶名
/// </summary>
public string Name { get; set;}
這樣寫的好處是只要用到這個屬性的地方,滑鼠移動上去都會顯示你的註解,對於後續維護上非常有幫助。
為屬性補上註解
/// <summary>
/// 銀行帳號
/// </summary>
public class Account
{
/// <summary>
/// 戶名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 帳號 13碼 0000000-666666
/// </summary>
public string Number { get; set; }
/// <summary>
/// 開戶時間
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 目前存款
/// </summary>
public decimal Cash { get; set; }
/// <summary>
/// 身分證字號
/// </summary>
public string RocId { get; set; }
}
Method()
方法(函數)
函數
如果學過早期程式設計的人,對函數一定不陌生,所有的程式語言靠函數來達成模組化設計。所以在學習Method之前我們先看一下什麼是函數。
//注意 這不是C# 是C語言
回傳類型 函數名稱(輸入值)
{
}
例如
//注意 這不是C# 是C語言
// 簡易家法的函數
int Add(int a ,int b)
{
return a + b;
}
//在某處呼叫使用函數來使用
int a;
a = Add(10+20);
函數有幾個重點
- 一段程式碼
- 把重覆的程式碼抽出來共用
- 固定輸出與輸入的類型
- 隱藏複雜的邏輯
- 每個函數內的變數都是彼此獨立不互相干擾
函數這個概念在程式設計上是很重要的里程碑,後續程式設計的變化其實就不大,如果你說物件導向不就是很大的變化,我認為物件則是一個更複雜版的函數而已,能夠把相關的屬性與函數集中在一段程式當中。
方法Method
多數物件導向的程式語言的函數就是類別中的方法,但功能更多。
- 有存取範圍,常用的是
public
大家都能存取private
只有類別內部能存取
- 可以不同的輸入值,但相同名稱的函數(稱為多載或多型、在後面的程式會講到這點)。
方法的命名重點
- 方法名稱,大駝峰 upper camel case
- 輸入值,小駝峰 lower camel case
public classs 物件名稱
{
public 回傳類型 方法名稱 (輸入值)
{
}
}
那們我們來擴充一下方法,假設我要做一個存款的功能
/// <summary>
/// 存款
/// </summary>
/// <param name="money">存款金額</param>
public void Save(decimal money)
{
//驗證不能存負值
if (money < 0)
{
return;
}
Cash += money;
}
完整的程式 Account.cs 按鍵頭展開
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
/// <summary>
/// 銀行帳號
/// </summary>
public class Account
{
/// <summary>
/// 戶名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 帳號 13碼 0000000-666666
/// </summary>
public string Number { get; set; }
/// <summary>
/// 開戶時間
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 目前存款
/// </summary>
public decimal Cash { get; set; }
/// <summary>
/// 身分證字號
/// </summary>
public string RocId { get; set; }
/// <summary>
/// 存款
/// </summary>
/// <param name="money">存款金額</param>
public void Save(decimal money)
{
//驗證不能存負值
if (money < 0)
{
return;
}
Cash += money;
}
}
}
這個寫Method 有幾個重點可以讓你寫起來更省力
- 一個Method盡量只做一件事情。
- 相關驗證寫Method前面。
- 命名要能展現「意圖」,例如SearchByName、Append。
新手寫程式的時候先記住這兩點
第一點:寫程式要寫的快有個很重要的要素,讀程式的時間比寫程式時間多,開發中八成的時間都在「看」程式,真的「寫」程式時間只有佔兩成,程式本身如果容易讀,你開發的時間就會大幅縮短。
第二點:無論是Class或Method,不要太多功能塞在一起, 這種塞在一起的作法英文為Supper Class或God Class,中文會叫做萬用類別,這樣做雖然感覺開發很快很直覺,但會造成超級難維護,最後你就會因為不想維護這個可怕的坑,然後離職。
我們目前已經得到一個可以存款的小類別了,現在可以開始寫主程式。
如何使用寫好的類別
把類別class變成物件object會經過instance的過程 ,像是把設計圖蓋成房子。
//跟新增一個變數一樣
類別名稱 物件名稱 = new 類別名稱();
//將Account intance 名為 peterAccount的類別
Account peterAccount = new Account();
Account maryAccount = new Account();
Account wishAccount = new Account();
就像用同一個設計圖蓋三間房子,裡面的格局都相同,但門牌號碼不同。
進行開戶與存款
先回到主程式Program.cs中
- 假設我們有個存戶叫做Petter Chen
- 要開一個戶頭編號叫做7000199-111122
- 開戶存入2000元
//程式碼要寫在Main當中
static void Main(string[] args)
{
//建立帳戶
Account petersAccount = new Account();
//設定銀行帳戶資料
petersAccount.Name = "Peter Chen";
petersAccount.Number = "7000199-111122";
petersAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
petersAccount.Save(2000);
//輸出帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.ReadKey();
}
開戶執行結果
多增加幾戶
static void Main(string[] args)
{
//建立Peter的帳戶
Account petersAccount = new Account();
petersAccount.Name = "Peter Chen";
petersAccount.Number = "7000199-111122";
petersAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
petersAccount.Save(2000);
//建立Marry的帳戶
Account marryAccount = new Account();
marryAccount.Name = "Marry Wang";
marryAccount.Number = "7000199-111332";
marryAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
marryAccount.Save(1000);
marryAccount.Save(500);
marryAccount.Save(50);
//建立Marry的帳戶
Account kenAccount = new Account();
kenAccount.Name = "Ken Lee";
kenAccount.Number = "7000189-132237";
kenAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
kenAccount.Save(1000);
//輸出帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.WriteLine($"帳戶名稱:{marryAccount.Name},帳戶號碼:{marryAccount.Number},開戶時間:{marryAccount.CreateTime},存款:{marryAccount.Cash}");
Console.WriteLine($"帳戶名稱:{kenAccount.Name},帳戶號碼:{kenAccount.Number},開戶時間:{kenAccount.CreateTime},存款:{kenAccount.Cash}");
Console.ReadKey();
}
目前的Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
internal class Program
{
static void Main(string[] args)
{
//建立Peter的帳戶
Account petersAccount = new Account();
petersAccount.Name = "Peter Chen";
petersAccount.Number = "7000199-111122";
petersAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
petersAccount.Save(2000);
//建立Marry的帳戶
Account marryAccount = new Account();
marryAccount.Name = "Marry Wang";
marryAccount.Number = "7000199-111332";
marryAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
marryAccount.Save(1000);
marryAccount.Save(500);
marryAccount.Save(50);
//建立Marry的帳戶
Account kenAccount = new Account();
kenAccount.Name = "Ken Lee";
kenAccount.Number = "7000189-132237";
kenAccount.CreateTime = DateTime.Now;
//進行存款 呼叫Save方法
kenAccount.Save(1000);
//輸出帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.WriteLine($"帳戶名稱:{marryAccount.Name},帳戶號碼:{marryAccount.Number},開戶時間:{marryAccount.CreateTime},存款:{marryAccount.Cash}");
Console.WriteLine($"帳戶名稱:{kenAccount.Name},帳戶號碼:{kenAccount.Number},開戶時間:{kenAccount.CreateTime},存款:{kenAccount.Cash}");
Console.ReadKey();
}
}
}
物件設定初始值
官方說明 如何使用物件初始設定式初始化物件 – C# | Microsoft Learn
如果class本身的Property 有設定為public {set;}
或{get;set;}
可以在new物件的時候直接設定初始值
例如我們戶名Property 為 public string Name { get; set; }
這樣我程式就能改為
Account petersAccount = new Account()
{
Name = "Peter Chen",
Number = "7000199-111122",
CreateTime = DateTime.Now,
};
直接在new
的時候就設定好object的初始值是比較漂亮的作法,程式碼的效率也會提升,作法是在new物件時,將object後加入{} ,然後在{}內寫入初始值,如有多個屬性要設定可以透過逗點分隔。
自動化
Visual Studio其實很先進,會對你程式碼提出一些建議,在可以改善的程式碼底下標記綠色線。只要先點綠色線後,最前面會出現一個小燈泡,點下去就會出現建議選項,在這邊按下去系統就會自動幫你把程式碼變成物件初始值。
重構程式碼-改為物件初始值
寫程式的一個概念就是要時常整理跟優化你的程式碼,這個動作在程式設計稱為重構。雖然不建議一開始就做所謂的最佳化,但是補補註解,調整一些寫法對於後續開發是非常重要的。
重構後的Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
internal class Program
{
static void Main(string[] args)
{
//建立Peter的帳戶
Account petersAccount = new Account()
{
Name = "Peter Chen",
Number = "7000199-111122",
CreateTime = DateTime.Now,
};
//進行存款 呼叫Save方法
petersAccount.Save(2000);
//建立Marry的帳戶
Account marryAccount = new Account
{
Name = "Marry Wang",
Number = "7000199-111332",
CreateTime = DateTime.Now
};
//進行存款 呼叫Save方法
marryAccount.Save(1000);
marryAccount.Save(500);
marryAccount.Save(50);
//建立Marry的帳戶
Account kenAccount = new Account
{
Name = "Ken Lee",
Number = "7000189-132237",
CreateTime = DateTime.Now
};
//進行存款 呼叫Save方法
kenAccount.Save(1000);
//輸出帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.WriteLine($"帳戶名稱:{marryAccount.Name},帳戶號碼:{marryAccount.Number},開戶時間:{marryAccount.CreateTime},存款:{marryAccount.Cash}");
Console.WriteLine($"帳戶名稱:{kenAccount.Name},帳戶號碼:{kenAccount.Number},開戶時間:{kenAccount.CreateTime},存款:{kenAccount.Cash}");
Console.ReadKey();
}
}
}
作業1-滾利息
- 設計一個方法,AddInterest(decimal interest) ,
- 年利率利息設定為0.70
作業2-重新命名Save方法
- 把存款的英文修正為Deposit(),正確的英文單字是這個。
- 測試修改後的程式
作業3-增加取款Withdraw方法
- 將Account.cs增加提款的Method → Withdraw()
- 提款動作要做的是→1檢查餘額是否足夠,不夠返回false,足夠進行扣款並返回true。
- 提款成功返回true,餘額不足返回false。
- 提款上限單筆為20,000。
作業4 – 重構程式碼-採用List
- 將這三個人的帳戶存入
List<Account> bankAccount
這個List當中。 - 用
for
印出每個人的帳號 - 用
foreach
印出每個人的帳戶 - 每個人戶頭都存入3000元,當作發振興卷。
作業1 滾利息解答
執行畫面
關鍵部分
/* Account.cs內 */
/// <summary>
/// 設定利息
/// </summary>
public decimal InterestRate { get; set; }
/// <summary>
/// 滾利息
/// </summary>
/// <param name="days">利息天數</param>
/// <returns>本次利息金額</returns>
public decimal AddInterest(int days)
{
// 利息計算公式:利息 = 本金 * 利率 * 天數 / 365
decimal interest = Cash * InterestRate * days / 365;
// 利息存入本金
Cash += interest;
return interest;
}
完整程式
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
internal class Program
{
static void Main(string[] args)
{
//設定利率,參考郵局活存利率為0.830%
const decimal interestRate = 0.0083m;
//建立Peter的帳戶
Account petersAccount = new Account()
{
Name = "Peter Chen",
Number = "7000199-111122",
CreateTime = DateTime.Now,
InterestRate = interestRate
};
//進行存款 呼叫Save方法
petersAccount.Save(2000);
//建立Marry的帳戶
Account marryAccount = new Account
{
Name = "Marry Wang",
Number = "7000199-111332",
CreateTime = DateTime.Now,
InterestRate = interestRate
};
//進行存款 呼叫Save方法
marryAccount.Save(1000);
marryAccount.Save(500);
marryAccount.Save(50);
//建立Marry的帳戶
Account kenAccount = new Account
{
Name = "Ken Lee",
Number = "7000189-132237",
CreateTime = DateTime.Now,
InterestRate = interestRate
};
//進行存款 呼叫Save方法
kenAccount.Save(1000);
//輸出帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.WriteLine($"帳戶名稱:{marryAccount.Name},帳戶號碼:{marryAccount.Number},開戶時間:{marryAccount.CreateTime},存款:{marryAccount.Cash}");
Console.WriteLine($"帳戶名稱:{kenAccount.Name},帳戶號碼:{kenAccount.Number},開戶時間:{kenAccount.CreateTime},存款:{kenAccount.Cash}");
Console.WriteLine("------------------------");
Console.WriteLine("增加一年利息");
Console.WriteLine("------------------------");
//計算利息
petersAccount.AddInterest(365);
marryAccount.AddInterest(365);
kenAccount.AddInterest(365);
//顯示增加利息後的帳戶資訊
Console.WriteLine($"帳戶名稱:{petersAccount.Name},帳戶號碼:{petersAccount.Number},開戶時間:{petersAccount.CreateTime},存款:{petersAccount.Cash}");
Console.WriteLine($"帳戶名稱:{marryAccount.Name},帳戶號碼:{marryAccount.Number},開戶時間:{marryAccount.CreateTime},存款:{marryAccount.Cash}");
Console.WriteLine($"帳戶名稱:{kenAccount.Name},帳戶號碼:{kenAccount.Number},開戶時間:{kenAccount.CreateTime},存款:{kenAccount.Cash}");
Console.ReadKey();
}
}
}
Account.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
namespace SundayBank
{
/// <summary>
/// 銀行帳號
/// </summary>
public class Account
{
/// <summary>
/// 戶名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 帳號 13碼 0000000-666666
/// </summary>
public string Number { get; set; }
/// <summary>
/// 開戶時間
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 目前存款
/// </summary>
public decimal Cash { get; set; }
/// <summary>
/// 身分證字號
/// </summary>
public string RocId { get; set; }
/// <summary>
/// 存款
/// </summary>
/// <param name="money">存款金額</param>
public void Save(decimal money)
{
//驗證不能存負值
if (money < 0)
{
return;
}
Cash += money;
}
/// <summary>
/// 設定利息
/// </summary>
public decimal InterestRate { get; set; }
/// <summary>
/// 滾利息
/// </summary>
/// <param name="days"></param>
/// <returns></returns>
public decimal AddInterest(int days)
{
// 利息計算公式:利息 = 本金 * 利率 * 天數 / 365
decimal interest = Cash * InterestRate * days / 365;
// 利息存入本金
Cash += interest;
return interest;
}
}
}
作業2 重新命名Save方法 解答
顯示命名設定,AI幫我補上建議名稱
我有按下Shitf+Enter,對要重新命名的部分進行檢查,這是Visual Studio 2022才有的。
重新命名的注意事項
Visual Studio本身有內建一個重新命名的方法,它會順便把所有引用到的部分也一起重新命名。
如果開發的版比較舊,在使用上要注意它不會重新命名這幾個地方:
.cshtml
(MVC的View)- .
aspx
(Webform的View) - 註解字串
這時候就要使用Ctrl+F ,用命名前的名稱去搜尋程式碼看有那邊使用過的,有個小技巧是可以先搜尋加上「.」的部分,代表有函數搜尋這部分。
0 Comments