存取修飾詞
存取修飾詞 | 說明 |
---|---|
public | 無任何存取限制。 |
internal | 只能在自已類別與專案(組件)中其它類別進行存取。(不包含其它專案)。 |
protected | 只能在自已類別和子類別中存取。 |
protected internal | 只能在目前專案(組件)與子類別存取。 |
private | 在自已類別存取。 |
封裝的使用
封裝的使用時機 :
- 封裝表示讓一個類別對其他類別隱藏特定資訊,這樣有助於防止程式發生臭蟲。
- 當你回頭編程已經有好一陣子沒有沒看程式碼時,很容易就會忘記當初你要它做什麼,那正是封裝能夠大展身手的地方。
封裝的精神
- 只要在必要時才讓欄位與方法為public
- 將物件想成黑箱。你並不在意該方法到底是怎麼運作的。你只在意它接受你提供的輸入,並回傳正確的結果。
- 減少程式BUG,因為相依性減少了。
封裝性不良好類別
首先我們先建立個,幾乎沒有使用到封裝的類別BagFamer,這個類別主要是計算該農場需要多少袋飼料來養牛。
農場所需飼料(袋) = 牛隻數量 * 每隻牛需要的飼料
BagOfFeed = NumberOfCows * FeedMulitplier
三個欄位
- FeedMulitplier : 存放一隻牛需要多少袋飼料。
- NumberOfCows : 存放這個農場有幾隻牛。
- BagOfFeed : 存放這個農場需要多少飼料。
Tip.共同遵循的約定與慣例。
假設有一欄位PeopleNumber
私有(private)欄位會表示 peropleNumber
公用(public)欄位會表示 PeropleNumber
一個方法
CalculateBagOfFeed() : 計算這個農場需要多少飼料。
//建立類別使用欄位儲存牛隻數量(NumberOfCows),並且乘上一個數字 (FeedMultiplier)
//,計算出需要多少袋飼料餵養牛。
public class BadFamer
{
//欄位存放一隻牛需要多少袋飼料,預設30
public const int FeedMultiplier = 30;
//欄位存放有幾隻牛
public int NumberOfCows;
//欄位存放需要有多少飼料
public int BagOfFeed;
//計算農場需要多少袋飼料的方法。
public void CalculateBagOfFeed()
{
BagOfFeed = NumberOfCows * FeedMultiplier;
}
}
BadFamer myFarmer;
public Form1()
{
InitializeComponent();
//實體化類別。
myFarmer = new BadFamer ();
}
private void button1_Click(object sender, EventArgs e)
{
//設定NumberOfCows欄位有幾隻牛。
myFarmer.NumberOfCows = (int)numericUpDown1.Value;
myFarmer.CalculateBagOfFeed();
textBox1.Text = "I need " + myFarmer.BagOfFeed + "bags of feed for " + myFarmer.NumberOfCows + " cows";
}
執行結果
雖然不使用封裝重構,可以得到正確的執行結果。但如果有一天,一位來維護你的類別的新手Coder(就是小弟我),來不小心加了一行.
myFarmer.BagOfFeed = 30;
變成下列程式碼。
private void button1_Click(object sender, EventArgs e)
{
//設定NumberOfCows欄位有幾隻牛。
myFarmer.NumberOfCows = (int)numericUpDown1.Value;
myFarmer.CalculateBagOfFeed();
myFarmer.BagOfFeed = 30;
textBox1.Text = "I need " + myFarmer.BagOfFeed + "bags of feed for " + myFarmer.NumberOfCows + " cows";
}
執行結果
這時你就GG了,這時是可以罵他,但你也該想想為什麼你寫的類別,為什麼這 BagOfFeed 這東西你明明只能讀,但為什麼你也開給他可以寫,不該出現的東西出現了
,這就代表封裝性沒有做好。
封裝性良好類別
接下來我們在建立一個封裝性良好的類別GoodFamer。
三個欄位
- numberOfCows : NumberOfCows屬性的支援欄位。存放有農場有幾隻牛。
- feedMultiplier : 存放每隻牛需要多少飼料。
- bagOfFeed: 存放農場需要多少飼料。
二個屬性
- BagOfFeed : 設立『唯讀』。讀時回傳bagOfFeed欄位。主要用來給別人看農場需要多少飼料。
- NumberOfCows : 設立『讀寫』。
讀時回傳numberOfCows欄位。主要用來給人知道農場有多少牛。寫時將值寫入numberOfCows欄位,並直接計算農場所需飼料存入bagOfFeed屬性。
public class GoodFamer
{
//會變成『NumberOfCows屬性(properties)』的支援欄位(backing field)
//不需要public的就設private
private int numberOfCows;
private const int feedMultiplier =30;
private int bagOfFeed;
//這個就是屬性
public int FeedMultiplier { get { return feedMultiplier; } }
//BagsOfFeed屬性,只可以讀取。
public int BagsOfFeed
{
get
{
//讀取時回傳bagOfFeed欄位。
return bagOfFeed;
}
}
//這是NumberOfCows屬性(properties)的宣告
public int NumberOfCows
{
get
{
//讀取NumberOfCows屬性,就會回傳numberOfCows欄位
return numberOfCows;
}
set
{
//會將值寫入numberOfCows欄位。
//並直接進行農場所需的飼料計算。並存入BagsOfFeed屬性.
numberOfCows = value;
bagOfFeed = numberOfCows * FeedMultiplier;
}
}
}
呼叫~
GoodFamer myFarmer;
public Form1()
{
InitializeComponent();
//實體化類別。
myFarmer = new GoodFamer ();
}
private void button1_Click(object sender, EventArgs e)
{
//設定NumberOfCows欄位有幾隻牛。
myFarmer.NumberOfCows = ( int)numericUpDown1.Value;
textBox1.Text = "I need " + myFarmer.BagsOfFeed + "bags of feed for " + myFarmer.NumberOfCows + " cows";
}
執行結果
從上面執行結果,還是和上支程式一樣,那我為何還需要改程式呢??假設我和上支程式碼做一樣的修改,增加一行
myFarmer.BagsOfFeed = 30
修改為如下程式碼。
private void button1_Click(object sender, EventArgs e)
{
//設定NumberOfCows欄位有幾隻牛。
myFarmer.NumberOfCows = ( int)numericUpDown1.Value;
//加入這行,試試看。
myFarmer.BagsOfFeed = 30
textBox1.Text = "I need " + myFarmer.BagsOfFeed + "bags of feed for " + myFarmer.NumberOfCows + " cows";
}
結果