物件導向系列菜單9-『物件導向特性-封裝(Encapsulation)』

摘要:物件導向系列菜單9-『物件導向特性-封裝(Encapsulation)』

 

包大人:這是秘密~~
包大人:要做的乾淨~懂嗎!?
 

 

正文開始
本文主題
「存取修飾詞』
『封裝的使用』
 

 

『存取修飾詞』
 
存取修飾詞 說明
public 無任何存取限制。
internal 只能在自已類別與專案(組件)中其它類別進行存取。(不包含其它專案)。
protected 只能在自已類別和子類別中存取。
protected internal  只能在目前專案(組件)與子類別存取。
private 在自已類別存取。
 
『封裝的使用』
 
封裝的使用時機
1.封裝表示讓一個類別對其他類別隱藏特定資訊,這樣有助於防止程式發生臭蟲。
2.當你回頭編程已經有好一陣子沒有沒看程式碼時,很容易就會忘記當初你要它做什麼
    ,那正是封裝能夠大展身手的地方。
 
 
封裝的精神
1.只要在必要時才讓欄位與方法為public
 
2.將物件想成黑箱
你並不在意該方法到底是怎麼運作的。你只在意它接受你提供的輸入,並回傳正確的結果。
 
3.減少程式BUG,因為相依性減少了
 
 
我們來建立兩程個類別範例來說明何謂『不良好封裝性』與『良好封裝性』。
 
程式說明
 
『封裝性不良好類別』
首先我們先建立個,幾乎沒有使用到封裝的類別BagFamer,
這個類別主要是計算該農場需要多少袋飼料來養牛。
 
農場所需飼料(袋) = 牛隻數量 * 每隻牛需要的飼料
BagOfFeed  =  NumberOfCows * FeedMulitplier
 
三個欄位
FeedMulitplier  : 存放一隻牛需要多少袋飼料。
NumberOfCows : 存放這個農場有幾隻牛。
BagOfFeed : 存放這個農場需要多少飼料。
 
一個方法
CalculateBagOfFeed() : 計算這個農場需要多少飼料。
Tip.
共同遵循的約定與慣例。
 
假設有一欄位PeopleNumber
私有(private)欄位會表示  peropleNumber
公用(public)欄位會表示  PeropleNumber

 //建立類別使用欄位儲存牛隻數量(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.Numb            erOfCows + " 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屬性。
FeedMultipler:設立『唯讀』。讀時回傳feedMultipler欄位。主要用來給別人看每頭牛需要多少飼料。

 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";
       
        }

 

執行結果
總結一下『封裝性』的概念就是
『不需要出現的東西就不要出現』

 


 

 

 



小弟才書學淺~請各位客官指教指教~~~

小弟日 : 你要知道自已不是帥哥,你才有可能變成帥哥 。