2012-06-24 63 views
2

雖然我理解實現/接口區別的價值,但我無法理解大多數面向對象系統在訪問私有成員時發生錯誤的原因。靜態語言的隱私

我確實不想訪問我的主程序中的私人成員。
但我想有測試和調試的訪問權限。

是否有任何理由發出錯誤而不是警告?我看到它的方式,我不得不編寫我可以測試的代碼,但是這不會使用語言支持接口,或使用語言支持,但在測試中遇到困難。

編輯

對於使用公共接口誰建議。你可以,但它不太方便。
在概念層面上,我發現隱私不關心誰或什麼時候很粗糙。
朋友類似乎是一個合理的解決方案。另一個可能是「所有公共」編譯器開關。

+4

解決方法是不寫測試,直接訪問被測對象的私有成員。您的測試應該在公共界面上運行。 –

+2

按照設計,不應私人成員有其他(公共)方法已經調用它們?私人方法的想法是細分一個班級的內部運作而不會使其公共界面複雜化。爲什麼你會寫一個沒有目的的私有方法(即一個公開的方法來調用它)? – Stecman

回答

1

我看到它的方式,我不得不編寫我可以測試的代碼,但那不支持接口的語言支持,或者使用語言支持,但是在測試時遇到困難。

爲什麼您需要訪問private變量和函數?要麼他們在某些時候被函數調用(不過是間接的),要麼他們只是不可訪問的代碼段,根本不應該存在,因爲沒有辦法調用它們。想想看,如果private方法完全是不可能從課外以任何方式調用,它是否會運行?

如果你真的想測試一個private方法,你可以把它放到它自己的類中。另外,如果它如此複雜以至於它確實需要單獨進行最佳測試,那麼它有可能首先有機會。另一種選擇是隻要你需要/想要測試它就公開,但實際上並沒有改變'真正'的代碼(把它留給private)。正如其他人所說,有些語言還具有的功能,幫助你測試這些方法通過將他們略多,如朋友C++,internal in C#package-private in Java.Occasionally the IDE's themselves even help out.

有沒有什麼好的理由去發出錯誤和不警告?

一大原因不是所以你不能打電話給他們,其他人不能打電話給他們。想象一下,你正在寫一個將被大量客戶使用的圖書館。你已經標記了他們不需要撥打private的所有內容,並且他們需要的所有功能都是公開的。程序員繼續前進,開始使用你的庫,用它編寫一堆代碼,並且自己和他們自己的客戶都生產出滿意的客戶。

幾個月後,你決定爲你的大規模成功的圖書館加油,並發現你需要做一些重構。因此,您[重命名,添加/刪除參數,刪除]一些private方法,但要小心保持所有公共方法的接口完全相同,以便升級無縫過程。 但是在此Universe中,編譯器僅在訪問private變量時發出警告而不是錯誤,並且幾個客戶端程序員編寫了調用這些private方法的代碼。現在,當他們嘗試升級到您的圖書館的新版本時,他們會遇到一堆真正的錯誤,因爲他們不能再調用這些private方法。現在,他們不得不花時間找出代碼出了什麼問題,並重新編寫了大部分代碼,他們不記得任何事情(我提到這是未來兩年?)。因此,他們必須徹底重新學習如何使用你的庫並重寫他們的客戶代碼,這對任何人來說都是無趣的。現在他們很不高興,因爲你太過分了,以至於在升級過程中逐字打破所有代碼並使他們的生活變得更加困難。

猜測當他們修復代碼時,他們研究並調用了新的private方法,因此如果您在發佈升級時決定更改界面,整個循環會重新開始。對你而言,稍微方便一點就是給你一堆不滿意的顧客。

等等,是不是他們打電話給我的私人方法的白癡?他們爲什麼不看警告?這是他們的錯,不是我的!

嗯,是的,這是他們的錯,他們可以通過注意這些警告來防止問題。但並不是每個人都是想要修正和理解警告的代碼質量的狂熱分子,並且大量的人忽略它們。問題是,如果編譯器發出嘗試訪問private變量和方法而不是警告的錯誤,則可以自己阻止整個事件,否則private關鍵字根本就不存在。你可能已經失去了一點時間,因爲這些方法很難測試,但是你已經獲得了讓那些不那麼聰明的人不會濫用你的代碼並將任何問題歸咎於你的問題的能力。

我最喜歡的軟件開發原則之一(以及一般的產品設計)是應該易於正確使用,或者不能正確使用。真正的私人成員是這種建議的體現,因爲它們使您的代碼無法正確使用。

[假設的反駁:]那麼,使用我的代碼的人應該足夠聰明,弄清楚。我要求他們只是花點時間正確使用代碼。

因此,您有意識地拒絕花費時間來提高代碼的質量並使其更易於使用?然後,我不想要什麼與你的代碼。顯然你的時間比你的客戶更重要,所以我會花2.5秒時間關閉你的項目的網頁,然後點擊下一個Google結果。你所使用的圖書館中有更多private的成員比你想像的要多得多,而光榮的是你不必花費你的時間毫秒來擔心它們,因爲它們對你完全是隱藏的,只會分散在public界面中提供的更簡單更好的方式。如果所有內容都是公開的或者是懦夫警告 - 私密的,那麼在你真正找到你想要的東西之前,你必須篩選更多的功能。

每當您在成員函數之前鍵入private時,您已經給了自己權力以任何方式在未來的任何時候更改它,因爲除了您之外,沒有人可以觸摸它。第二個人試圖訪問它,他們會得到一個停止顯示的錯誤,因爲編譯器有你的背面,並且當你已經以更加可用的形式提供了他們需要的所有東西時,他們不會讓它們對你的代碼做任何愚蠢的事情在你的public界面。

是的,它會使現在測試變得稍微困難​​一點,但它也確保了您在將來重構時可以不必擔心它,並且使您的代碼更容易批次人們使用。繼續並暫時公開它(我有點像你的'全公開編譯器開關的想法:),但不要忘記當你完成你的時候把它切換回來,你的客戶都可以用簡單的更具適應性的代碼。 :D

+0

我個人認爲,無法訪問「風險」功能的用戶同樣可能會做「正確的事情」,因爲他正在發明一種新的巧妙方式,在拍攝自己的同時坍塌該區域中的多個建築物腳丫子。我的責任是告訴他們哪些功能有風險,但不強制訪問。 – sabof

+0

什麼我不喜歡嚴格的封裝是,我沒有得到儘可能多的方式來探索我的程序。在具有良好工具的語言中,它可能不成問題。 – sabof

+0

@sabof他可能有很好的機會讓它正確無誤,但爲什麼不只是拿走他的槍,所以他不能在自己的腳首先射擊自己? :) –

0

顯而易見的原因是,太多人似乎忽略了很多(全部)警告。在某些語言中(例如Python),就像您所說的那樣 - 「私有」的東西基本上是針對直接使用它的外部代碼的建議,但編譯器不會強制執行該操作。

至於它的語言之間有多大的意義,使我懷疑變化 - 在像C++,對他們的態度(「防止墨菲,而不是馬基雅維利」)可以被視爲爲理由作爲一個警告而不是錯誤。

我認爲可以肯定地說,在Ada中,至少可以得到一個較冷的接收(這並不是說我認爲它會被C++程序員熱烈收到),只是他們可能不會像大多數Ada程序員那樣討厭這個想法)。

另一方面,我不得不懷疑一個無法通過外部接口進行測試(至少合理)的類的設計。在罕見的(應該是罕見的,無論如何)你不能的情況下,我認爲使測試類成爲朋友(用C++的說法,儘管許多其他人也有類似的概念)很容易證明。

+0

我看到Ada程序員可能不喜歡這個想法。沿着可調整嚴格的路線可能會讓每個人都滿意 - 動態發展與靜態保證。 – sabof

0

有幾個優勢,具有完整的封裝:

  • 安全。強封裝的強類型OOP語言可以對程序中數據的安全性有一定的保證。 Java語言的設計考慮到安全性和安全性,因此某些庫類(例如StringSecurityManager)不能訪問其字段。這可以防止惡意代碼對這些對象造成不良影響,並允許代碼假定對象是安全的。

  • 可維護性。保留private字段和方法private的主要原因之一是允許實現無縫地更改;只要沒有對公共接口進行更新,使用更新類的代碼就可以在沒有更改的情況下工作。如果您允許訪問private字段,然後更改實施,則可能會破壞無限量的代碼。

  • 穩定性/可驗證性/可測性。類通常在其字段上施加不變量 - 例如,動態數組的實現可能需要一個字段,用於跟蹤實際上與元素總數對應的空間使用量。允許人們隨意訪問private字段,即使發出警告,也可以打破這些不變量。如果沒有依賴不變量的能力,就很難或不可能推斷代碼的正確性。另外,如果你確實在代碼的某個地方破壞了一個不變量,你可能會想到程序中的每一段代碼都可以訪問該對象,因爲它們中的任何一個都可能訪問private字段。通過強封裝,這些不變式不會中斷,並且通過封裝私有機制或封裝私有機制進行半封裝,可以看到的代碼量是有限的。

至於你的測試問題 - 許多語言允許封裝在某些情況下被打破; C++有friend,Java有package-private等,所以這個類可以說「通常你不能碰這些,但是可以有例外。」然後,您可以將測試代碼設置爲friend或與主類相同的程序包,以便對其進行更徹底的測試。

希望這會有所幫助!

+1

我從來沒有被說服封裝 - >安全(至少不是OO意義上的)的說法。 C++有原始指針,Java有反射等。 –

+0

@ OliCharlesworth-的確如此,但C++類並不是爲了安全而設計的,而Java則是。 Java中的安全管理器被設計爲使得關鍵類不能被反映到(例如,字符串,系統等)中,並且可以對其進行自定義,以便可以防止訪問您所選擇的關鍵類。我會說它不是經常以這種方式使用,但Java確實提供了這種安全性。 – templatetypedef

0

我看到它的方式是你需要忘記訪問對象中的任何東西,除非你有辦法在那個對象的接口中做這件事。如果您試圖直接訪問實現特定的私有成員,我認爲正確的面向對象系統應該發佈錯誤(而不是警告)。最近我參加了Kevlin Henney關於此主題的一次精彩演講,我發現它非常有用,可以在這裏查看副本:http://www.infoq.com/presentations/It-Is-Possible-to-Do-OOP-in-Java(注意它主要是關於java,但也包括與其他OO系統的比較)

用於測試大部分時間我發現大部分被測試的代碼都被公共接口調用覆蓋。只有在極少數情況下,我需要使用運行時反射等方式來獲得絕對100%的覆蓋率。

0

我即將發佈,「強大的封裝強制功能可以讓您的老闆不會踩到您的私人會員。」直到我意識到這可能聽起來錯了,但第二個想法是 可能是正確的。