2013-06-30 79 views
5

我的問題涉及Java,但它也可以應用於C#。我想知道爲什麼每個人都建議使實例變量私有而不是使它們變爲保護爲什麼建議將實例變量聲明爲私有?

讓我們考慮一下吧。私有變量沒有被子類看到,所以如果我需要訪問或更改我的子類中超類的變量,我不得不使用一些訪問器和增變器方法,如getMyPrivateVariablesetMyPrivateVariable。但是當你擴展某個類並繼承它的成員時,這就像你直接在子類中聲明它們一樣。因此,從邏輯上講,這意味着子類也應該可以直接訪問實例變量,併爲設計具有受保護變量的類提供了一個案例。我知道這樣的做法會破壞封裝,但這在繼承的情況下似乎是無關緊要的,因爲在這種情況下,所有情況都好像是超級成員在sublcass中聲明的一樣,所以sublcass擁有「自然權利」能夠直接訪問其成員,而不管它們是否被繼承。在我看來,封裝對於通過對象繼承樹之外的其他對象與對象接口更重要。

所以,我的問題是爲什麼大家建議將類的實例變量聲明爲私有而不是保護?

+0

這是一個適合programmers.stackexchange.com而不是StackOverflow的問題。 – m3th0dman

+0

不是_everyone_。但從你的文本看來,你有點'保護';無論如何,做你認爲正確的事。 – fge

+5

僅僅因爲一個類允許繼承並不意味着它想允許子類對其內部不變式的任意腐敗。使字段(和一些方法)「私人」允許這一點。 – dlev

回答

1

你自己回答 - 封裝。

例如,您有一個抽象的Cat類。這定義了成員變量的速度 - 即它運行的速度。

抽象類還定義了明顯更新速度的最終運行方法。

現在 - 如果Cat的子類 - 例如Moggy或Tabby可以直接訪問和修改「速度」,然後可以打破運行方法。

所以最好保持它在開始的地方。如果需要,您也可以在本地聲明它。

0

,如果我需要訪問或更改我的子類繼承的變量,我不得不使用一些訪問[...]

有你有一個錯誤:private成員繼承。您可能會將「繼承」的含義與子類的實例擁有其超類的所有成員這一事實相混淆。

查看私有成員沒有被繼承的含義的最好方法是觀察子類可以聲明自己的私有成員,並且這永遠不會導致與超類的同名私有成員發生衝突。兩者和平共處。在這種情況下,protected成員其實它的公共API的一部分:設計一個類specfically由子類中使用,只有當

成員宣佈protected。大多數課程是而不是設計爲公共擴展,但宣佈他們final往往不是一個選項。如果這些類擁有其所有成員protected,那麼這將等於使它們成爲public,因爲任何客戶端代碼都可以輕鬆地創建其虛擬子類,而不會向父級添加任何內容,但會暴露其內部。

+0

Marko,它讓我錯了。我知道私有變量不能被子類訪問,但受保護的是。這就是我的問題的要點 - 爲什麼要從子類中隱藏超類的數據結構。 – akhilless

+0

您確實說過要訪問不可訪問的繼承變量;我回答說,「他們不是遺傳的」。 –

+0

我在詢問關於聲明實例變量private而不是protected的有效性。你引用的部分說「私有變量不能被子類看到」,所以我知道它們不是被繼承的。我糾正了錯字,並且從該處刪除了「繼承」這個詞,使我的思路更加清晰。另一方面,您不認爲製作一個虛擬子類暴露了對超類的繼承(保護)變量的訪問,實際上暴露了sublcass的內部,因爲您不能在超類的對象上調用這些方法? – akhilless

0

請考慮以下「經驗法則」:從您的班級以外可見的任何內容都將成爲合同與外部世界的一部分。爲了保持您的自由,儘可能以最小的影響修改您的代碼,您的目標是將可見性限制在儘可能最低 - 人們通常不會限制他們的自由,除非他們被迫。

換句話說,您必須有理由聲明除private以外的其他成員。一旦你有一個強有力的理由,只提高能見度到最低可能程度(第一選擇應該是包私人/默認知名度)。那是因爲你應該完全控制你的包中的代碼(或者至少有一些控制權),所以可以單獨執行那些變化。作爲一個側面說明,「包私人」是唯一可見級別(public除外),可以應用於頂級類本身。因此,您應該考慮從其包中未使用的類中刪除public修飾符。

protected能見度「逃避」了您的控制範圍,因爲任何客戶都可能依賴於該特定變量或方法。

至於public,一個好的做法是隻將它用於在您實現的接口中聲明的方法。

0

如果你讓你的實例變量受到保護,並且可以繼承你的類(因爲它不是final),那麼每個人都可以繼承你的類並在你不期望的時候改變你的實例變量。這極大地提高了您的功能不符合您的需求的機會。您必須處理各種類型的如何使用,這使得您很難確保實例變量的每個可能的變化都會在其發生更改的任何可能時間點產生預期結果。

0

恕我直言,這是一個哲學問題。但我想這是一個爲實例變量訪問添加安全層的問題。

通過讓他們通過getter和setter來暴露他們,您保證他們將被正確訪問(例如沒有超出範圍的值)關於您的班級的角色。你也正在準備將來的干預,通過孤立責任(例如,如果在某個時候你意識到某些處理應該系統地完成一個特定的變量,那麼你只有一種方法來完善,理論上不接觸其他任何東西,更重要的是不會破壞整個程序的功能)。您只需提供一個getter方法即可自由定義其中的一些。

所以基本上它增加了一層安全性,並讓您更好地控制變量。

此外,由於它們被稱爲實例變量,因此只有實際的實例才能直接訪問它們對我來說是有意義的。

0

OOP的實質是發送消息,意味着favorising 行爲超過數據

避免暴露變量的原因是儘可能使您的軟件最靈活靈活

客戶不應該從各地收集一些數據並自行實施邏輯(邏輯不屬於他們的責任),他們應該Tell! Don't Ask!。 他們不應該掌握所需的算法,這應該是目標類的角色。

通過讓您的變量protected在基類(或最終類..)中,您允許子類改變它們,而且很多時候,子類可能沒有知識也沒有責任去做。 它通常會導致一些神祕的錯誤,比如從子類向字段的基類分配一個意外的值。 當然,在某些情況下需要protected,但只有當子類關心的是相同的責任時。

因此,總是讓你的變量/方法範圍儘可能地限制。您的代碼將因此受到保護,靈活,易於進行單元測試(因爲集中在一個地方),並在將實例變量暴露給客戶端時免除許多常見的錯誤。尤其是,您的班級可以在不破壞客戶端代碼的情況下更改其內部結構。

此外,當你不處理數據結構時避免getter/setter。事實上,這將促進行爲方法。

事實上,在95%的情況下,getter/setter非常差(不實施有價值的邏輯),並且只是最終運行以使您的變量變爲public/protected

相關問題