芥子須彌
----封裝
作者:HolyFire
說(shuō)起面向?qū)ο驩OP首先就有人大喊著封裝
究竟封裝是什么呢,為什么要封裝?
是的,本來(lái)并沒(méi)有封裝,封裝是由于人們的需要才產(chǎn)生的,就如同計(jì)算機(jī)來(lái)到人間,編程語(yǔ)言進(jìn)入你的大腦,自然而然。
在沒(méi)有封裝的時(shí)候,人們一樣在編程,并沒(méi)有因?yàn)榉庋b的出現(xiàn)使得猿猴變成了人,所以封裝沒(méi)有那么神秘,可怕。
想象一下,我們生活里也有很多封裝:食品被放在袋子里,用來(lái)防止混入灰塵和昆蟲(chóng)侵蝕;戴上太陽(yáng)鏡,防止紫外線傷害眼睛;錢(qián)和貴重物品放在保險(xiǎn)柜里,防止心術(shù)不正的人。
好了,我們看出一點(diǎn),封裝的一個(gè)作用是保護(hù)我們的東西。
在生活中,有很多慣例,這里要提到一點(diǎn),那就永真式,這是一個(gè)表示在無(wú)論什么情況下都為真的式子,當(dāng)然這是一種理想的情況,但人們往往喜歡創(chuàng)造這樣的東西,就象“水往低處流” 。牛頓說(shuō)“由于地球引力,所以蘋(píng)果是往地上掉的”幸虧有這樣的道理,我們才有水喝,有蘋(píng)果吃。當(dāng)然了在地球上很難找出反例,所以我們無(wú)需考慮蘋(píng)果飛上天的可能性。又如人的聽(tīng)覺(jué)范圍是2kHZ~~20kHZ,如果有人說(shuō)地球上會(huì)有一個(gè)人的聽(tīng)覺(jué)超出這個(gè)范圍,我一點(diǎn)異議都沒(méi)有,但是我還是把人的聽(tīng)覺(jué)作為2kHZ~~20kHZ來(lái)處理,應(yīng)為概率論上有一句,小概率的事是不會(huì)發(fā)生的,我不打算證實(shí)他,我只是想利用他,我只處理2kHZ~~20kHZ的聽(tīng)覺(jué)范圍,在絕大多數(shù)領(lǐng)域里,這樣做足夠了,讓在這方面有特別要求的人掙扎去吧,少處理這些個(gè)別的人會(huì)帶來(lái)更多的好處。
我們又能發(fā)覺(jué)到,封裝的好處能降低復(fù)雜度。
我想沒(méi)有人會(huì)愚蠢到將一只羊和一只牛相加,得到兩只羊或兩只牛這樣的結(jié)果,但是兩只動(dòng)物這樣的結(jié)果卻是可以接受的。
這樣看來(lái),封裝他能夠降低出錯(cuò)的可能性。
封裝所做的遠(yuǎn)遠(yuǎn)不是這些。
等等,各位心中是不是充滿了疑惑。
講了這么久,為什么不說(shuō)明封裝到底是什么呢,文中并沒(méi)有提到啊。
聰明的朋友,封裝并不是什么東西,也不是什么方法,他是人們考慮和解決問(wèn)題的思路,他就是你的思想,就是你的靈感一閃,就是你的錦囊妙計(jì)。封裝就是人們?yōu)榱烁玫墓芾砗褪褂檬挛锏姆桨福梢宰屇愀奖悖踩淖瞿阆胱龅氖拢L(zhǎng)久以來(lái),充滿智慧的杰出者們摸索出一些使用封裝來(lái)解決問(wèn)題的辦法。
在編程的應(yīng)用上,我們看看封裝給我們帶來(lái)的好處吧。
由于計(jì)算機(jī)里,一些都數(shù)字化了,所以信息都是存放在很多很多的存儲(chǔ)單元里的,由于硬件的限制,這些存儲(chǔ)單元都有確實(shí)的大小。
首先我們來(lái)談?wù)劚Wo(hù)我們的數(shù)據(jù)不被隨便訪問(wèn),這正是我提到的。
比如說(shuō)一個(gè)員工可以看到自己的工資,但如果他能夠修改的話,只怕人人都想去這個(gè)公司工作了。修改工資的數(shù)據(jù),萬(wàn)萬(wàn)不行,萬(wàn)萬(wàn)不行,但是如果人人都不能修改工資這一數(shù)據(jù),那也不行啊,財(cái)會(huì)需要修改關(guān)于工資的數(shù)據(jù)。
這里我使用面向?qū)ο箝_(kāi)發(fā)而設(shè)計(jì)的C++語(yǔ)言來(lái)實(shí)現(xiàn)他,因?yàn)樗菫槊嫦驅(qū)ο笤O(shè)計(jì)的,所以實(shí)現(xiàn)起來(lái)比較方便。沒(méi)學(xué)過(guò)C++的人先要看一看基本概念,至少要理解private,public,protected,friend等關(guān)鍵字的概念。
我們來(lái)理解一下我們要做的事,公司里有很多人,人人都有工資,一些是員工,員工用工號(hào)來(lái)區(qū)別,一些是財(cái)會(huì),而財(cái)會(huì)也是員工,員工能察看工資,而財(cái)會(huì)還能修改工資。
我們有三個(gè)角色,人,員工,財(cái)會(huì),要做兩件事,員工察看工資,財(cái)會(huì)修改工資,然后理清他們的關(guān)系
人有姓名,年齡,性別 這三樣是我們需要處理的,我們要做的是處理工資,一些無(wú)關(guān)的信息就可以省略,習(xí)慣上每個(gè)部門(mén)都需要人的這三個(gè)信息
人 = { 姓名 , 年齡 , 性別 }
員工是人,財(cái)會(huì)是人,財(cái)會(huì)是員工,員工有工資,為了區(qū)別員工每個(gè)員工有工號(hào)
員工察看工資,財(cái)會(huì)修改工資
員工 ={ 人 , 工資 ,工號(hào) , 察看工資 }
財(cái)會(huì) ={ 員工 , 修改工資 }
//下面三句代碼是使用標(biāo)準(zhǔn)函數(shù)庫(kù),可以節(jié)省我們很多功夫,方便我們理解我們要理解的,略過(guò)繁枝小節(jié)
#include <iostream>
#include <string>
using namespace std;
class Man{
public:
enum SexType { Mele , Female };//枚舉類(lèi)型,性別只有男女兩種,這里不考慮人妖,如果輸入不是這樣種類(lèi)型,編譯器會(huì)報(bào)警。類(lèi)型轉(zhuǎn)換中如果不是者兩個(gè)值,也會(huì)報(bào)警,這樣我們減少了誤輸入引起的錯(cuò)誤。
private: //變量不能亂操作,設(shè)定為私有,只有類(lèi)的成員函數(shù)才能操作,起到保護(hù)作用
string Name;//姓名,string是標(biāo)準(zhǔn)函數(shù)庫(kù)里提供的類(lèi),可以方便的處理字符串
unsigned Age; //年齡,由于年齡不可能是負(fù)數(shù),所以用unsigned表示,這樣可以防止邏輯錯(cuò)誤
SexType Sex;//性別
public: //對(duì)外的接口,當(dāng)然要開(kāi)放了
string GetName( void ){ return Name; }//得到人的名字
void SetName( string const& name )//改變?nèi)说拿郑@里預(yù)先檢查了名字是否合法
{
if( str == "" )
return;
Name = name;
}
unsigned GetAge( void ){ return Age; }//得到人的年齡
void SetAge( unsigned age )//改變?nèi)说哪挲g,由于員工50歲就退休了,所以50以下的才合法
{
if( age >= 50 )
return;
Age = age;
}
SexType GetSex( void ){ return Sex; } //得到人的性別
Void SetSex( SexType sex ){ Sex = sex }//改變?nèi)说男詣e
};
class Accountant;
class Employee : public Man{
private:
unsigned ID;//工號(hào)
protected://雖然要加以保護(hù),但是他的后繼類(lèi)財(cái)會(huì)要操作的
unsigned Pay; //工資
public:
unsigned GetID( void );//取得工號(hào)
void SetID( unsigned );//改變工號(hào)
unsigned GetPay( void ){ return Pay; }//察看工資
friend class Accountant;//由于財(cái)會(huì)能夠修改所有員工的工資,所以要將訪問(wèn)權(quán)信托給財(cái)會(huì)
};
class Accountant : public Employee{
public:
void SetPay( unsigned pay ){ Pay = pay; } //改變自己的工資
void SetPay( Employee * man , unsigned pay ){ man->Pay = pay; }; //改變別人的工資
};
當(dāng)然這是經(jīng)過(guò)精心設(shè)計(jì)后的封裝,簡(jiǎn)化了結(jié)構(gòu),正因?yàn)橐婚_(kāi)始細(xì)心的分析,才使得設(shè)計(jì)可以輕松自如,歸根結(jié)底是由于思想正確,好了,封裝是一種思想,我們現(xiàn)在將他體現(xiàn)了出來(lái)。
再看這個(gè)例子里,工資的類(lèi)型是unsigned,非負(fù)整數(shù),呵呵,大家都不愿意到工資為負(fù)的公司工作吧,這里簡(jiǎn)化問(wèn)題是從人們的慣例的角度出發(fā)的,如果你的老板考慮工資為負(fù)的情況,那么…^_^
現(xiàn)在一個(gè)粗心的財(cái)會(huì)不小心改錯(cuò)了,他多敲了一個(gè)0,哇歐,請(qǐng)客請(qǐng)客,但這個(gè)財(cái)會(huì)可就慘了,這樣的好事不會(huì)發(fā)生,不準(zhǔn)發(fā)生,老板青著臉狂吼著。
設(shè)計(jì)不得不加上一個(gè)工資的上限,沒(méi)辦法啦,現(xiàn)在國(guó)家規(guī)定的嗎。
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;
}
};
可以看出封裝的作用就是減少出錯(cuò)的可能,方便靈活的運(yùn)用類(lèi)型
在上面的例子里我們看到,類(lèi)class是由一些變量和函數(shù)組成的,這些變量和函數(shù)是類(lèi)的一部分,我們稱(chēng)之為成員,變量就是成員變量,函數(shù)當(dāng)然就叫成員函數(shù)了。為什么要這樣呢,我們考慮一下,事物是由物質(zhì)和運(yùn)動(dòng)組成的,表現(xiàn)物質(zhì)的一面我們通常描述他的一些屬性,即他擁有什么,表現(xiàn)一個(gè)運(yùn)動(dòng)我們通常使用一個(gè)過(guò)程,要將一個(gè)事物的信息描述清楚就需要這兩樣?xùn)|西。在長(zhǎng)期的實(shí)踐中程序員達(dá)成一個(gè)共識(shí),將事物的特性(也就是它擁有的)稱(chēng)之為屬性,他能夠產(chǎn)生的行為稱(chēng)之為方法,數(shù)字化以后就是成員變量和成員函數(shù),他們的組成的整體就是類(lèi)(類(lèi)型),這個(gè)類(lèi)型將作為一個(gè)單獨(dú)的節(jié)點(diǎn)考慮,就像例子中的Man,我們不會(huì)說(shuō)這是一個(gè)姓名,年齡等等的組合體,而是將他作為一個(gè)類(lèi)--class Man考慮,從而簡(jiǎn)化了問(wèn)題。細(xì)小的事物組合成大的事物,大的事物組合成更大的事物,這樣下去,再大難題也可以化作小模塊來(lái)處理,這正是封裝誘人的地方和他的使命。
需要補(bǔ)充的是,既然我們把數(shù)據(jù)保護(hù)起來(lái),那么如何讓用戶(hù)訪問(wèn)這些數(shù)據(jù)就是一個(gè)問(wèn)題了,在上面的例子中看出public:申明的方法,用戶(hù)是可以使用的,而我們正是通過(guò)這些方法將數(shù)據(jù)的信息告訴使用者,這里我們將描述方法的部分就叫做接口(在C++里,就是類(lèi)中成員函數(shù)的聲明,用戶(hù)一般只對(duì)public:部分的接口感興趣,所以有人建議將public:部分的內(nèi)容寫(xiě)在顯眼的地方,比如靠類(lèi)的頂部),也有人說(shuō)是界面,也就是類(lèi)和外界溝通和交流使用的渠道,所以接口是很重要的,他直接關(guān)系到你的類(lèi)使用的方面。
而使用者使用類(lèi)的某個(gè)接口的時(shí)候就象是通知這個(gè)類(lèi)型使用某個(gè)行為,就象是傳遞一個(gè)消息給他一樣,我們把使用接口稱(chēng)之為傳遞消息,而類(lèi)被調(diào)用方法稱(chēng)之為接受消息。
現(xiàn)在我們可以出定義:封裝就是將事物的內(nèi)容和行為都隱藏在實(shí)現(xiàn)里,用戶(hù)不需要知道其內(nèi)部實(shí)現(xiàn),這是大量程序員反復(fù)勞動(dòng)后得出的一致結(jié)論。這樣的好處就是使用方便,易于維護(hù),任何一樣都可以使程序員為之心動(dòng)。當(dāng)然我們不能保證高效,但是不意味著使用封裝就沒(méi)有高效的可能,如果在封裝的基礎(chǔ)上保證高效的話,我實(shí)在找不出理由來(lái)拒絕他。
|
溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!