芥子須彌----封裝 (轉)

gugu99發表於2008-06-24
芥子須彌----封裝 (轉)[@more@]

 

芥子須彌

  ----封裝:namespace prefix = o ns = "urn:schemas--com::office" />

作者:HolyFire

說起面向首先就有人大喊著封裝

究竟封裝是什麼呢,為什麼要封裝?

是的,本來並沒有封裝,封裝是由於人們的需要才產生的,就如同來到人間,語言進入你的大腦,自然而然。

在沒有封裝的時候,人們一樣在程式設計,並沒有因為封裝的出現使得猿猴變成了人,所以封裝沒有那麼神秘,可怕。

想象一下,我們生活裡也有很多封裝:食品被放在袋子裡,用來防止混入灰塵和昆蟲侵蝕;戴上太陽鏡,防止紫外線傷害眼睛;錢和貴重物品放在保險櫃裡,防止心術不正的人。

好了,我們看出一點,封裝的一個作用是保護我們的東西

在生活中,有很多慣例,這裡要提到一點,那就永真式,這是一個表示在無論什麼情況下都為真的式子,當然這是一種理想的情況,但人們往往喜歡創造這樣的東西,就象“水往低處流” 。牛頓說“由於地球引力,所以蘋果是往地上掉的”幸虧有這樣的道理,我們才有水喝,有蘋果吃。當然了在地球上很難找出反例,所以我們無需考慮蘋果飛上天的可能性。又如人的聽覺範圍是20HZ~~20kHZ,如果有人說地球上會有一個人的聽覺超出這個範圍,我一點異議都沒有,但是我還是把人的聽覺作為20HZ~~20kHZ來處理,應為機率論上有一句,小機率的事是不會發生的,我不打算證實他,我只是想利用他,我只處理20HZ~~20kHZ的聽覺範圍,在絕大多數領域裡,這樣做足夠了,讓在這方面有特別要求的人掙扎去吧,少處理這些個別的人會帶來更多的好處。

我們又能發覺到,封裝的好處能降低複雜度

我想沒有人會愚蠢到將一隻羊和一隻牛相加,得到兩隻羊或兩隻牛這樣的結果,但是兩隻動物這樣的結果卻是可以接受的。

這樣看來,封裝他能夠降低出錯的可能性

封裝所做的遠遠不是這些。

等等,各位心中是不是充滿了疑惑。

講了這麼久,為什麼不說明封裝到底是什麼呢,文中並沒有提到啊。

聰明的朋友,封裝並不是什麼東西,也不是什麼方法,他是人們考慮和解決問題的思路,他就是你的思想,就是你的靈感一閃,就是你的錦囊妙計。封裝就是人們為了更好的管理和使用事物的方案,它可以讓你更方便,更的做你想做的事,長久以來,充滿智慧的傑出者們摸索出一些使用封裝來解決問題的辦法。

在程式設計的應用上,我們看看封裝給我們帶來的好處吧。

由於計算機裡,一些都數字化了,所以資訊都是存放在很多很多的單元裡的,由於的限制,這些儲存單元都有確實的大小。

首先我們來談談保護我們的資料不被隨便訪問,這正是我提到的。

比如說一個員工可以看到自己的工資,但如果他能夠修改的話,只怕人人都想去這個公司工作了。修改工資的資料,萬萬不行,萬萬不行,但是如果人人都不能修改工資這一資料,那也不行啊,財會需要修改關於工資的資料。

這裡我使用物件導向開發而設計的C++語言來實現他,因為他是為物件導向設計的,所以實現起來比較方便。沒學過C++的人先要看一看基本概念,至少要理解private,public,protected,friend等關鍵字的概念。

我們來理解一下我們要做的事,公司裡有很多人,人人都有工資,一些是員工,員工用工號來區別,一些是財會,而財會也是員工,員工能察看工資,而財會還能修改工資。

我們有三個角色,人,員工,財會,要做兩件事,員工察看工資,財會修改工資,然後理清他們的關係

人有姓名,年齡,性別 這三樣是我們需要處理的,我們要做的是處理工資,一些無關的資訊就可以省略,習慣上每個部門都需要人的這三個資訊

人 = { 姓名 , 年齡 , 性別 }

員工是人,財會是人,財會是員工,員工有工資,為了區別員工每個員工有工號

員工察看工資,財會修改工資

員工 =  { 人 , 工資 ,工號 , 察看工資 }

財會 =  { 員工 , 修改工資 }

//下面三句程式碼是使用標準庫,可以節省我們很多功夫,方便我們理解我們要理解的,略過繁枝小節

#include    

#include

using namespace std;

class Man{

public:

  enum SexType { Mele , Female };    //列舉型別,性別只有男女兩種,這裡不考慮人妖,如果輸入不是這樣種型別,會報警。型別轉換中如果不是者兩個值,也會報警,這樣我們減少了誤輸入引起的錯誤。

private:  //變數不能亂操作,設定為私有,只有類的成員函式才能操作,起到保護作用

  string Name;  //姓名,string是標準函式庫裡提供的類,可以方便的處理字串

  unsigned Age; //年齡,由於年齡不可能是負數,所以用unsigned表示,這樣可以防止邏輯錯誤

    SexType Sex;  //性別

public:  //對外的介面,當然要開放了

  string GetName( void ){ return Name; }  //得到人的名字

  void SetName( string const& name )   //改變人的名字,這裡預先檢查了名字是否合法

  {

  if( str == "" )

    return;

  Name = name;

  }

  unsigned GetAge( void ){ return Age; }   //得到人的年齡

  void SetAge( unsigned age )     //改變人的年齡,由於員工50歲就退休了,所以50以下的才合法

    {

  if( age >= 50 )

    return;

  Age = age;

  }

  SexType GetSex( void ){ return Sex; }    //得到人的性別

  Void SetSex( SexType sex ){ Sex = sex }   //改變人的性別

};

class Accountant;

class Employee : public Man{

private:

  unsigned ID;    //工號

protected:    //雖然要加以保護,但是他的後繼類財會要操作的

  unsigned Pay;    //工資

public:

  unsigned GetID( void );  //取得工號

  void SetID( unsigned );  //改變工號

  unsigned GetPay( void ){ return Pay; }  //察看工資

friend class Accountant;  //由於財會能夠修改所有員工的工資,所以要將訪問權信託給財會

};

class Accountant : public Employee{

public:

  void SetPay( unsigned pay ){ Pay = pay; } //改變自己的工資

  void SetPay( Employee * man , unsigned pay ){ man->Pay = pay; }; //改變別人的工資

};

當然這是經過精心設計後的封裝,簡化了結構,正因為一開始細心的分析,才使得設計可以輕鬆自如,歸根結底是由於思想正確,好了,封裝是一種思想,我們現在將他體現了出來。

再看這個例子裡,工資的型別是unsigned,非負整數,呵呵,大家都不願意到工資為負的公司工作吧,這裡簡化問題是從人們的慣例的角度出發的,如果你的老闆考慮工資為負的情況,那麼…^_^

現在一個粗心的財會不小心改錯了,他多敲了一個0,哇歐,請客請客,但這個財會可就慘了,這樣的好事不會發生,不準發生,老闆青著臉狂吼著。

設計不得不加上一個工資的上限,沒辦法啦,現在國家規定的嗎。

class Accountant : public Employee{

  enum MaxPay{ MAXPAY = 8000 };

public:

  void SetPay( unsigned pay )

    {

  if( pay > MAXPAY )

    return;

  Pay = pay;

  }

  void SetPay( Employee * man , unsigned pay )

  {

  if( pay > MAXPAY )

    return;

    man->Pay = pay;

  }

};

可以看出封裝的作用就是減少出錯的可能,方便靈活的運用型別

在上面的例子裡我們看到,類class是由一些變數和函式組成的,這些變數和函式是類的一部分,我們稱之為成員,變數就是成員變數,函式當然就叫成員函式了。為什麼要這樣呢,我們考慮一下,事物是由物質和運動組成的,表現物質的一面我們通常描述他的一些屬性,即他擁有什麼,表現一個運動我們通常使用一個過程,要將一個事物的資訊描述清楚就需要這兩樣東西。在長期的實踐中員達成一個共識,將事物的特性(也就是它擁有的)稱之為屬性,他能夠產生的行為稱之為方法,數字化以後就是成員變數和成員函式,他們的組成的整體就是類(型別),這個型別將作為一個單獨的節點考慮,就像例子中的Man,我們不會說這是一個姓名,年齡等等的組合體,而是將他作為一個類--class Man考慮,從而簡化了問題。細小的事物組合成大的事物,大的事物組合成更大的事物,這樣下去,再大難題也可以化作小模組來處理,這正是封裝誘人的地方和他的使命。

需要補充的是,既然我們把資料保護起來,那麼如何讓訪問這些資料就是一個問題了,在上面的例子中看出public:申明的方法,使用者是可以使用的,而我們正是透過這些方法將資料的資訊告訴使用者,這裡我們將描述方法的部分就叫做介面(在C++裡,就是類中成員函式的宣告,使用者一般只對public:部分的介面感興趣,所以有人建議將public:部分的內容寫在顯眼的地方,比如靠類的頂部),也有人說是介面,也就是類和外界溝通和交流使用的渠道,所以介面是很重要的,他直接關係到你的類使用的方面。

而使用者使用類的某個介面的時候就象是通知這個型別使用某個行為,就象是傳遞一個訊息給他一樣,我們把使用介面稱之為傳遞訊息,而類被方法稱之為接受訊息

現在我們可以出定義:封裝就是將事物的內容和行為都隱藏在實現裡,使用者不需要知道其內部實現,這是大量程式設計師反覆勞動後得出的一致結論。這樣的好處就是使用方便,易於維護,任何一樣都可以使程式設計師為之心動。當然我們不能保證高效,但是不意味著使用封裝就沒有高效的可能,如果在封裝的基礎上保證高效的話,我實在找不出理由來拒絕他。

2001/8/12

丁寧 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1006053/,如需轉載,請註明出處,否則將追究法律責任。

相關文章