<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    冒號和他的學生們(連載26)——訪問控制

     

    冒號和他的學生們

     

    26.訪問控制

    夫輕諾必寡信,多易必多難                                    ——《老子·德經》

     

    問號提問:“信息隱藏是否專指用private來控制訪問?”

    “這正是我們的下一個焦點。”冒號微頷,“訪問修飾符access modifier)除了可以應用于類成員外,在JavaC#中還能應用于整個類。public類自然是公開的,而缺省的類在Java C#中分別僅對同一packageassembly開放。”

    逗號不覺有異:“這有什么講究嗎?”

    “當然。越是基本的語法越講究,也越容易被忽視。”冒號的嘴角漾著一絲微笑,“許多人在寫類時習慣上來就敲‘public class’,或者通過IDE自動生成類的雛形,缺省的一般都是public類。這樣看似無害,但絕非好習慣。事實上大多數類是不需要公開的,這是一種更高層次的信息隱藏。每個packageassembly,如果設計合理,應該是具有相關功能的類和接口的集合。其中不少只是內部使用的,毫無必要公諸于眾。”

    引號了然于心:“這與對象封裝類似,既向客戶明確了接口類,又可消弭修改內部類對客戶的影響。”

    嘆號仍心存疑慮:“OOP是鼓勵和支持重用的。好不容易開發出來的類卻深藏不露,豈不可惜?客戶也許一時用不上,但指不定以后會用上。”

    “問得好!這也是大多數人的心理。按照你的邏輯,我同樣可以說:這個類的方法是好不容易開發出來的,藏起來太可惜了,統統public吧!”冒號惟妙惟肖地學著嘆號的神態和腔調,把眾人都逗樂了。

    嘆號心欲辯而口難言。

    “重用是令人興奮的,合理的重用既節省了開發時間,又節省了維護時間,代碼也顯得更簡潔優美,可謂一舉多得。但是——”冒號一轉話鋒,“過猶不及,過度追求重用也會造成濫用和誤用。一方面,開發者容易沉溺于局部重用的妙處而忽略整體的設計,淡忘所開發類最核心的職責;另一方面,一旦所重用的類或方法發生改變,所有的重用者均受牽連,先前節省的時間或許會加倍地償還。”

    引號深有感觸地說:“難就難在如何把握這個度啊!”

    “任何一門技藝到了高級階段,都是‘度’的學問。”冒號一如既往地推而廣之,“初級程序員的理想是為所欲為——能用編程解決一切問題;中級程序員的理想是盡善而為——追求最佳解決方案;高級程序員的理想是有所為有所不為——重在整體設計的選擇,能抵制局部技巧的誘惑;最高理想是無為而無不為——無論宏觀設計還是微觀實現,均非刻意選擇,卻自然合度。”

    句號心念一動:“這四個階段可分別用四句廣告詞來代表:從全球通的‘我能’,到奧運會的‘更快、更高、更強’,到安踏的‘我選擇,我喜歡’,最后是馬爹利的‘心意有別,心中有度’。”

     “到底是時尚小青年,我的推而廣之到你這兒變成了廣而告之啦。”冒號半夸半謔,“書歸正傳,我們再說說類成員的訪問修飾符。”

    冒號在黑板上畫了一張表格——

    范圍" 語言

    C++

    Java

    C#

    無限制

    Public

    Public

    public

    子類或同一包

    Protected

    protected internal

    同一類或子類

    Protected

    private protected(已棄用)

    protected

    同一包

    package(缺省)

    internal

    同一類

    private(缺省)

    Private

    private(缺省)

    “其中publicprivate是兩個極端,一個沒有限制,一個僅限于同一類。JavaC#C++多了個包(packageassembly)的概念,相應也多了package(缺省)和internal的修飾符。”冒號解說道,“值得注意的是,Java中的protected相當于C#protected internal,不僅可被同類和子類訪問,還能被同一包內的任何類訪問。而C++C#中的protected只能被同類和子類訪問,相當于Java中曇花一現的private protected。”

    逗號急欲得知:“選擇這些修飾符有什么訣竅嗎?”

    冒號回應:“一個基本原則是盡可能地使用限制性更強的修飾符。即使以后改變主意,再放寬限制也不遲。相反,將一個修飾符收窄就要顧忌對客戶的影響了。尤其是域成員,沒有特殊理由都應該是private的,除非類是一個用作儲存的具體數據類型或內部類inner class)。在JDK源代碼中有不少packageproctected域成員甚至public域成員,絕不能以之為榜樣。順便說一句,C++C#中缺省的成員修飾符是private,顯然比Java中缺省package更科學一些。”

    問號刨根問底:“為什么特別強調域成員呢?”

    冒號條分縷析:“域成員代表對象的狀態,從運行方面看,若外界隨意讀取和改動,將無法保證內在邏輯的一致性;從設計方面看,屬結構性信息,極易變化;從接口方面看,公開接口都是以方法而非域的形式出現的。這些都要求隱藏域成員。”

    引號思路很清晰:“既然域成員一般都用private,那關鍵是如何選擇方法成員的訪問修飾符了。”

    “如果將每個類看作一個服務者,它向不同范圍內的客戶承諾不同的服務,或者說提供了層次化的服務。以Java為例,每一個public方法成員即是向所有類提供的服務;protected方法成員對該類的子類和同一package下的類提供服務;默認的package方法成員僅對同一package下的類提供服務;private方法成員則只對該類本身提供服務。那么如何具體界定一個服務的范圍呢?大多時候這是一個偽問題。”說到這里,冒號有意停頓了一會,查看大家的反應。

    眾人臉上果然滿是狐疑之色。

    “因為合理設計的服務,其內容與范圍往往是密不可分的。一個服務如果已經設計好了,甚至已經實現了,而此時尚未決定其使用者的范圍,是否有些荒謬?當然,荒謬其實也是現實中的一種常態。”冒號語帶反諷,“作為一個抽象數據類型的類,其核心是抽象接口,因此首先應該設計公共接口,它們的修飾符自然都是public。如果該類是一個抽象類abstract class)——此‘抽象’與抽象數據類型的‘抽象’意義有所不同,暫且不表——那么可能會有一些為其子類提供的服務,它們的修飾符自然該是protected。”

    問號聽得仔細:“難道非抽象類就不能有protected的接口嗎?”

    冒號回道:“從語法上說當然可以。但一般不建議繼承非抽象類,因而protected的意義就不大了。至于個中緣由,留待下節課再解釋。”

    嘆號追問:“那package服務和private服務呢?”

    冒號應答:“package一般作為library的單位,因此package方法成員存在的唯一理由是僅為該library服務,但這種情況相對少見。說到private方法成員,已談不上是真正的服務,純粹是實現細節。由于它的改動不會影響客戶,因此采用private訪問控制不需要任何理由,不采用它才需要理由。”

    眾人聽得頻頻點頭。

    冒號總結道:“從軟件應變的角度來看,訪問控制是對修改所帶來的副作用的控制。具體地說,如果修改僅僅涉及到private成員,那只要檢查該類的源代碼即可;如果修改涉及到package成員,只需檢查該類所在的package內的所有類。雖然這些類可能很多,但仍可控制,畢竟package是封閉的;如果修改涉及到protected成員,則不僅要檢查該類所在的package內的所有類,還需檢查該類的子類,如果該類本身是public,涉及的類可以超出該package的范圍,已難以真正掌控;如果修改涉及到public成員,那就意味著任何類都可能調用該接口,也就可能因此而無法編譯、運行和工作。因此訪問控制越松的成員,輻射范圍越廣,軟件重用的效率越高,承擔的責任越大,修改的代價也越大。成熟的程序員對publicprotected接口的設計一定是慎之又慎,往往在其上花的功夫更甚于具體代碼的編寫。”

    逗號似有些不服:“可是誰又能保證接口永遠不變呢?”

    “所以JavaC#才分別提供了deprecatedobsolete以將方法標記為過時啊。”冒號笑言以對,“當然這是不得已而為之的下策,可以理解為設計者對使用者的一種致歉。”

    見眾人并無共鳴,冒號心道:響鼓也需重錘,遂言:“看來你們感觸還不深,原因是缺乏一種關鍵的意識——客戶意識。客戶意識對一個程序員的重要性,絲毫不亞于對一個企業的重要性。”

    逗號忍不住問:“您一再提到客戶,究竟什么是客戶?”

    “這里的客戶當然不是一般所指的軟件終端消費者,而是指軟件中間消費者或重用者,即調用該軟件的代碼或代碼編寫者。”冒號作了個名詞解釋,“客戶意識的缺乏有幾種原因。首先,不是每個人都有機會開發大型、關鍵的軟件,許多程序員的客戶主要是他自己或少數幾個開發組成員,修改軟件影響到的代碼不多,影響到的人也不多,沒有真正吃過設計不當的苦頭。其次,開發庫和框架的人畢竟是少數,大多數人開發的代碼主要是自己調用或針對終端消費者的。即使他們寫了一些可重用的代碼,如果代碼質量不被認可,也可能無人采用。當一個人習慣于自彈自唱時,是很難培養客戶意識的。最后,正如我們在對象范式中指出的,過程式編程鼓勵自頂向下,而OOP鼓勵自底向上。顯然,頂是底的客戶。問題是許多OOP程序員仍習慣于過程式編程的風格,所設計的類或接口主要是調用其他的類或接口,而不是被調用。換句話說,他們設計的代碼主要角色是客戶,而不是客戶的服務者。”

    一番理論令眾人心服口服。

    引號關心地問:“如何培養客戶意識呢?”

    “如果認識到客戶意識的重要性,培養起來并不難。”冒號帶著安慰的口吻,“謹記一點:輕諾者,必寡信。每一個public類、每一個非private成員,都是一份承諾。在沒有明確職責、沒有準備承擔變更后果之前,請采用最嚴格的訪問控制。有了客戶意識,才有接口責任感。千萬不要為追求廉價的重用而輕易擴大接口范圍,莫以自身之便而致客戶之不便,莫以一時之便而致長期之不便。另外,單元測試對培養客戶意識很有幫助。它不僅僅能發現程序的邏輯缺陷,還能發現程序的設計缺陷。因為測試代碼就是最典型的客戶代碼,它能讓你站客戶的角度重新審視自己的接口設計。”

    posted on 2008-08-03 18:39 鄭暉 閱讀(1953) 評論(1)  編輯  收藏 所屬分類: 冒號和他的學生們

    評論

    # re: 冒號和他的學生們(連載26)——訪問控制 [未登錄] 2008-08-03 21:54 Rebollo

    好,此篇讓我有一種茅塞頓開的感覺,正學習JAVA中,為修飾符的變化而必存諸多疑問,而今此些已疑問不再。

    不知道這本書叫《編程那些事兒》如何?呵呵  回復  更多評論   

    導航

    統計

    公告

    博客搬家:http://blog.zhenghui.org
    《冒號課堂》一書于2009年10月上市,詳情請見
    冒號課堂

    留言簿(17)

    隨筆分類(61)

    隨筆檔案(61)

    文章分類(1)

    文章檔案(1)

    最新隨筆

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产精品亚洲综合专区片高清久久久| 成年女性特黄午夜视频免费看| 亚洲精品国产va在线观看蜜芽| 中文字幕亚洲综合久久综合| 成人黄18免费视频| 亚洲人成www在线播放| 一二三四视频在线观看中文版免费| 亚洲精品国产情侣av在线| 中文字幕免费在线观看| 亚洲福利视频网站| 在线视频观看免费视频18| 亚洲免费综合色在线视频| 国产a级特黄的片子视频免费| 精品国产亚洲第一区二区三区| 免费一级毛片不卡在线播放 | 亚洲天堂一区二区三区四区| 中文字幕乱码免费视频| 亚洲熟妇AV乱码在线观看| 国产精品免费小视频| 精品乱子伦一区二区三区高清免费播放 | 亚洲国产精品日韩| 最近免费字幕中文大全| 91亚洲自偷手机在线观看| 在线观看免费人成视频| 久久久久亚洲AV无码去区首| 国产精品亚洲高清一区二区| 中国黄色免费网站| 亚洲综合在线观看视频| 毛片免费在线观看网站| 一级黄色免费网站| 精品日韩亚洲AV无码一区二区三区| 国产精品成人免费一区二区 | 在线观看免费人成视频色| 色婷婷亚洲一区二区三区| 在线观看亚洲av每日更新| 91香焦国产线观看看免费| 亚洲七久久之综合七久久| 亚洲综合av永久无码精品一区二区| 久久久久国产免费| 在线观看亚洲免费视频| 亚洲人成在线影院|