本篇擷取重點:
一、封裝的目的
封裝(Encapsulation)的目的,是將程式碼切割成許多模組(Module),使各模組之間的關連性降到最低,這麼一來比較不會產生「牽一髮而動全身」的狀況,降低模組間相互依賴的程度,也等於是降低複雜度,讓開發與維護更容易。
事實上,沒有人用「模組」一詞來稱呼封裝的結果,而是稱為「類別」,把模組一詞做更高階的包裝用途。因此我們應該將「類別」視為封裝的結果,把「模組」視為整個程式切割出來的許多片段。在OO的世界,一般來說,一個程式有多個模組,一個模組內包含多個類別。
封裝是以資料為核心,將相關的資料放在一起,把會用到這些資料的函式也放進來,等於將資料和函式放在一起。儘管有的語言還有其它東西,例如 Event(事件)、Property(屬性),但是從內部來看,這些都是函式的變形。
為了和非OO的世界做出區隔,OO也做了一些名詞上的改變,將Function(函式)改稱為Method(方法)、將Call(呼叫)改稱為Invoke(調用)。但是新舊詞彙基本上還是通用的。
二、封裝 能見度之影響
封裝的目的既然是要「降低互相依賴的程度」,就牽涉到能見度的問題:這個「類別/方法/欄位」該不該暴露給別的模組、同一個模組的不同類別、自己的「次類別」、友伴類別(Friend Class)、內部類別(Inner Class)?這就是所謂的「能見度」(Visibility)。
我們當然希望盡可能降低能見度,才能「降低互相依賴的程度」。別人不需要知道的,就不要讓它知道,這就是所謂的「資訊隱藏」(Information Hiding)。
最該被隱藏的是資料。極致的封裝主義者,主張所有資料一定都不可以直接被外部(包括次類別)存取。
上面提到,封裝將相關的資料和使用到這些資料的方法包成類別。最理想的狀況是,讓資料能見度降到最低,外面完全看不見,留下的對外介面(Interface)只剩下方法(Method)。換句話說,每個物件的對外介面(Interface)是一些方法的集合,完全沒有資料。
設定能見度不是一件容易的事,往往需要深思熟慮。特別是對於設計「框架」(Framework)的人來說,能見度設定得太寬,造成資訊隱藏效果不佳,可能會帶來相當多負面效果(例如複雜度提高、程式容易出錯……等);能見度設定得太緊,則造成效率變差、擴充程度變差(有些設計因而做不出來)。
參考資料:
https://www.ithome.com.tw/node/45903 (大推薦!!)
==================================================================
貼心小補充:
未經過封裝的物件,外面的程式就可以任意存取物件的狀態。
在C#程式中,實作封裝動作的方式,就是在類別宣告時,透過【private存取修飾詞】,將需要封裝的成員私有化。
參考資料:
https://www.delightpress.com.tw/bookRead/skup00007_read.pdf
==================================================================
明日預定探討課題: