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

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

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

    冒號(hào)和他的學(xué)生們(連載27)——接口服務(wù)

     

    冒號(hào)和他的學(xué)生們

     

    27.接口服務(wù)

    律己宜嚴(yán),待人宜寬                                          ——《洪應(yīng)明·菜根譚》

     

    嘆號(hào)幡然反省:“以前我們做OOP編程時(shí),總是專注于如何利用其他類來解決問題,而較少考慮自己設(shè)計(jì)的類對(duì)其他類的影響。”

    引號(hào)翻開以前的筆記:“前面提過,OOP的世界是民主制的,所有對(duì)象都是獨(dú)立而平等的公民,有權(quán)利尋求服務(wù),也有義務(wù)提供服務(wù)。看來我們是光惦著權(quán)利而忘了義務(wù)了。”

    冒號(hào)繼而提出:“作為服務(wù)的提供者,最重要的是講誠(chéng)信。首先,服務(wù)要有可靠性,不能陽奉陰違——即接口必須履行它的承諾;其次,服務(wù)要有穩(wěn)定性,不能朝令夕改——即接口一經(jīng)公開,不得隨意變更。”

    句號(hào)迅即領(lǐng)悟:“從抽象的角度看,服務(wù)的可靠性保證了規(guī)范抽象,服務(wù)的穩(wěn)定性保證了數(shù)據(jù)抽象。”

    “孺子可教也!”冒號(hào)喜贊道,“相比而言,前者更為重要,但遺憾的是,只有后者才有法律保障——如果接口被廢棄或其簽名發(fā)生變化,固然會(huì)牽連客戶,至少還可通過編譯器來發(fā)現(xiàn)和修改;而規(guī)范只是語義上的契約,沒有語法上的約束,不在編譯器的監(jiān)管范圍之內(nèi)。”

    引號(hào)插言:“編譯器管不著,那只有靠單元測(cè)試了。”

    “這正是單元測(cè)試的主要目的。”冒號(hào)很認(rèn)同,“此外,高質(zhì)量的服務(wù)還要有純粹性完備性Unix有一個(gè)哲學(xué):‘一個(gè)程序只做一件事,但要做好’。用在OOP上,則是:‘一個(gè)類只提供一套服務(wù),但要完善’。譬如,同為手機(jī),老式的大哥大提供的服務(wù)是純粹的,現(xiàn)代的智能手機(jī)則不是——除了打電話,還能攝像、聽音樂、打游戲、上網(wǎng)等等,完全是手機(jī)與掌上電腦的結(jié)合體。又如,同為通訊工具,手機(jī)提供的服務(wù)是完備的,而BP機(jī)提供的服務(wù)是不完備的——只能接收信息,不能發(fā)送信息。”

    嘆號(hào)搖頭晃腦:“提供的服務(wù)過多則不純粹,過少則不完備。如此設(shè)計(jì)出的類是不是要達(dá)到‘增一分則肥,減一分則瘦’的美人標(biāo)準(zhǔn)啊?”

     “編程畢竟是門實(shí)踐活兒,完美無缺的設(shè)計(jì)如夢(mèng)中佳人,可以追求卻難以企及。”冒號(hào)笑了笑,“其實(shí)關(guān)鍵不在于服務(wù)數(shù)量的多寡,而在于服務(wù)的一致性和關(guān)聯(lián)性。連貫一致的服務(wù)是良好的抽象與封裝的結(jié)果,同時(shí)也是‘高聚合、低耦合’的保證。”

    “作一個(gè)服務(wù)的提供者真不容易啊。”問號(hào)嘆道,“那么,作為服務(wù)的享受者有什么講究嗎?”

    逗號(hào)鼻腔里發(fā)出共鳴聲:“哈,享受服務(wù)還需要講究嗎?”

    “當(dāng)然有。”冒號(hào)斷然道,“作為服務(wù)的享受者,最重要的是講規(guī)矩。享受人家的服務(wù),自然得按人家的規(guī)則,否則服務(wù)將得不到保障。比如,你可以在超市的貨架上任意選取商品,但不能偷偷溜進(jìn)貨艙去取。”

    逗號(hào)辯道:“可貨艙想進(jìn)也進(jìn)不去啊。正如合適的封裝,是禁止客人進(jìn)入私有接口的。”

    冒號(hào)作一引喻:“我們不妨這么假設(shè),貨艙的正門掛著‘非工作人員莫入’的牌子。但是你偶然發(fā)現(xiàn),通往洗手間的過道盡頭正好是貨艙的后門,既沒有上鎖,也沒有掛牌。請(qǐng)問你會(huì)不會(huì)大搖大擺地走進(jìn)去?”

    逗號(hào)啞口無言。

    冒號(hào)循循善誘:“超市的工作人員也許不該為圖方便而開放后門,但那是管理者的事,作為客戶顯然不應(yīng)乘虛而入。商品從貨艙到貨架之前可能會(huì)有裝箱、拆箱、條碼打印、條碼掃描等操作,客戶直接從貨艙拿貨無疑將破壞這種程序,于人于己皆無益處。同樣地,作為他人代碼的客戶,就應(yīng)按他人所設(shè)計(jì)的方式去重用,如此才能保證預(yù)期的效果。至于他人代碼是否有效杜絕了一切可能的漏洞,那是監(jiān)管軟件質(zhì)量的負(fù)責(zé)人的職責(zé)。”

    引號(hào)表示理解:“這就好比客戶購(gòu)買了一款產(chǎn)品,卻不按使用說明書進(jìn)行操作,由此而引起的一切后果,廠家概不負(fù)責(zé)。”

    “就是這個(gè)理兒。”冒號(hào)輕錘桌面,“當(dāng)然事物是一分為二的。生活中有一個(gè)司空見慣的現(xiàn)象:許多行人跨越護(hù)欄、橫穿馬路。一方面,行人應(yīng)該遵守交通規(guī)則,不應(yīng)破壞道路的‘封裝性’。另一方面,有些交通設(shè)計(jì)者沒有‘以人為本’的客戶意識(shí),為行人提供的斑馬線、天橋或隧道之間相距過遠(yuǎn)。從客觀上說,不夠完備的服務(wù)是導(dǎo)致行人違規(guī)的一大誘因。”

    此言顯見深得人心——幾乎人人都當(dāng)過道路封裝的破壞分子。

    冒號(hào)接著問:“提個(gè)問題:當(dāng)你們?cè)谑褂靡粋€(gè)類或其中的某個(gè)方法時(shí),對(duì)其用法存疑,即使閱讀注釋文檔也無濟(jì)于事,怎么辦?”

    嘆號(hào)順嘴說道:“看源代碼唄。”

    “看源代碼是一種很好的學(xué)習(xí)和借鑒他人的方式,但不宜作為用法參考。”冒號(hào)否定道,“且不說源代碼有可能無法獲取,既便能夠,從中提煉出的用法也不一定可靠,更何況具體實(shí)現(xiàn)隨時(shí)可能變化。再打個(gè)比方,如果你不清楚如何設(shè)置一個(gè)鬧鐘,應(yīng)該去看看說明書。如果說明書仍不解決問題,最好詢問廠家,而不是揭開鬧鐘的后蓋去研究它的運(yùn)行機(jī)制,即使你真是個(gè)鐘表行家。”

    “所以應(yīng)該直接咨詢代碼的作者。”逗號(hào)發(fā)現(xiàn),過早搶答往往會(huì)掉入老冒的陷阱。這回學(xué)乖了,等嘆號(hào)落坑后才胸有成竹地應(yīng)招。

    “方向正確!”冒號(hào)肯定后再次考問,“對(duì)方應(yīng)以何種方式回答?”

    “可以口頭,也可以書面啊。”逗號(hào)答畢,隱隱覺得還是著了道。

    果然,冒號(hào)搖搖頭:“正確的做法是,對(duì)方應(yīng)通過改進(jìn)并提交的文檔來解釋。該過程可多次循環(huán),直至問題解決。只有這樣,主客雙方的代碼維護(hù)者——包括當(dāng)前的和將來的——才能真正受益。”

    問號(hào)深究:“但假如無法聯(lián)系到原作者呢?比如包括JDK庫(kù)在內(nèi)的軟件?”

    冒號(hào)回答:“除了盜版的商業(yè)軟件,都應(yīng)該能聯(lián)系到原作者。當(dāng)然,如果與作者使用的不是同一源碼控制庫(kù),上述做法也是可以變通的。好在無論是JDK庫(kù),還是正規(guī)的第三方軟件,文檔注釋應(yīng)該都足夠清晰,許多還會(huì)提供示例代碼。如果這些還不能讓你明白,要么是該軟件不值信賴,也就沒有重用的價(jià)值;要么是你自身的理解問題,只有求助有識(shí)之士了。”

    句號(hào)體會(huì)到:“由此可見,封裝的代碼不僅要屏蔽客戶代碼的訪問,最好還能屏蔽客戶代碼開發(fā)者的訪問。這樣既鼓勵(lì)代碼作者多寫規(guī)范文檔,又鼓勵(lì)代碼用戶多讀規(guī)范文檔。一切以規(guī)范為中心,而不以源碼實(shí)現(xiàn)為中心。”

    “非常好的建議!”冒號(hào)豎起拇指,“訪問控制只是個(gè)玻璃罩,能防止亂動(dòng)的雙手,卻防止不了偷窺的雙眼。它至多只能維護(hù)語法上的封裝和信息隱藏,而語義上的封裝只有靠規(guī)范來維護(hù)。對(duì)程序員而言,前者是一種需要學(xué)習(xí)的知識(shí),后者是一種需要培養(yǎng)的素質(zhì)。”

    嘆號(hào)覺得腦子里仍是半清半濁:“能舉個(gè)語義上違反封裝的例子嗎?”

    冒號(hào)爽快地接受請(qǐng)求:“第一個(gè)例子是上節(jié)課談到對(duì)象封裝時(shí)作為反例的User類,其中getBirthday直接返回了內(nèi)部域birthday的引用。如果你在調(diào)用getBirthday后對(duì)返回值進(jìn)行修改,就是一種違反封裝的行為。”

    嘆號(hào)有些愕然:“那不是User類本身首先違反封裝原則的嗎?”

    冒號(hào)食指微揚(yáng):“不錯(cuò),User類的作者錯(cuò)在授人以隙,而你錯(cuò)在乘人之隙。”

    眾人一陣哄笑,嘆號(hào)面紅耳赤,仿佛真的犯了錯(cuò)似的。

    “剛才我們說過,超市開放貨艙后門屬管理不善,而客戶鉆進(jìn)去取貨屬不守規(guī)矩。類似地,行人橫穿馬路的問題也有兩方面的因素。”冒號(hào)重提前例,“說回User類,其設(shè)計(jì)者肯定不希望客戶通過此種方式來修改birthday,否則也不會(huì)提供setBirthday的接口。”

    逗號(hào)頗為不服:“可是setBirthday中除了簡(jiǎn)單的賦值什么也沒干哪!”

    “哈哈,又忍不住偷看源代碼了吧!”冒號(hào)逮了個(gè)正著,“你怎么能保證User類的作者哪天不心血來潮,在setBirthday中寫一些不同尋常的代碼?不要輕視任何一個(gè)接口,哪怕它暫時(shí)只有一個(gè)空語句的實(shí)現(xiàn)。事實(shí)上,許多空接口就是為將來的功能擴(kuò)展預(yù)留的,隨時(shí)可能被充實(shí),或者被子類覆蓋。”

    逗號(hào)心里話:得,又掉溝里了!

    冒號(hào)續(xù)道:“第二個(gè)例子涉及Java中的Swing。一般說來,如果一個(gè)組件的可視化性質(zhì)如位置、尺寸等發(fā)生改變,都需要重新布局(layout )。凡是Swing組件(component )都要調(diào)用revalidate 方法。絕大多數(shù)情況下,setTextsetFontsetIcon等方法的實(shí)現(xiàn)中會(huì)自動(dòng)調(diào)用revalidate,但仍有少數(shù)例外。規(guī)范文檔中又語焉不詳,令人困惑。為保證不受源碼變動(dòng)的影響,同時(shí)免除記憶之困,最好在一個(gè)組件所有與布局相關(guān)的變化完畢后,專門調(diào)用一次revalidate。以輕微的性能代價(jià)換來長(zhǎng)治久安,無疑是正確的。相反,依賴源代碼而非規(guī)范文檔編程,顯然是危險(xiǎn)的。如果說第一個(gè)例子直接破壞了封裝,有可能馬上被察覺,該例則隱蔽得多——只要在所依賴的源代碼不變,一切都正常。然而一旦有變,后果難以預(yù)料。”

    引號(hào)不免有些感慨:“一般人熟悉JDKAPI文檔多過熟悉源碼,尚且可能犯依賴源碼編程的錯(cuò)誤。如果重用同一開發(fā)組的代碼,甚至是本人的代碼,對(duì)源碼非常熟悉,偏偏文檔還匱乏,這種錯(cuò)誤更是在所難免。”

    “意識(shí)到這一點(diǎn)就是很大的進(jìn)步啊。”冒號(hào)欣慰道,“再舉一例。有時(shí)在使用一個(gè)類時(shí),你很想重用其中一個(gè)protected方法,但當(dāng)前所在的客戶類既不是其子類,所在的package也不同。怎么辦?”

    句號(hào)承認(rèn):“以前的確碰到這樣的問題,第一感覺是恨那作者太小氣:為什么不干脆將其設(shè)為public與眾共享?轉(zhuǎn)念一想,大不了寫個(gè)繼承的子類,別的事不做,專門把那些protected方法轉(zhuǎn)化為public。”

    “是不是這樣?”冒號(hào)在黑板上飛快地寫下——

    class Reserved

    {

        protected void f(){/**/}

        protected int g(){/**/}

        …

    }

    class Open extends Reserved

    {

        public void f(){super.f();}

        public int g(){return super.g();}

        …

    }

    見句號(hào)點(diǎn)頭,冒號(hào)問:“你不覺得有何不妥嗎?”

    “很俗很暴力。”句號(hào)的自評(píng)令眾人噴飯。

    冒號(hào)分析道:“你既然那么希望調(diào)用某個(gè)protected方法,說明它一定不平凡,但為何作者遮遮掩掩、不愿公開呢?假若他的設(shè)計(jì)是合理的,那么只有一個(gè)解釋:它是為內(nèi)部或子類服務(wù)的,本就不打算對(duì)外開放。你所需要的服務(wù)要么是設(shè)計(jì)者刻意回避的,要么接口另有所在,說不定還恰好調(diào)用了你所需要的方法呢!”

    一束光芒從眾人腦際劃過。

    冒號(hào)又補(bǔ)充道:“不輕易公開他人的protected成員還有一個(gè)理由。正因?yàn)?/span>protected的接口比public使用的范圍狹窄得多,接口變動(dòng)的可能性往往也更大,客戶應(yīng)該慎用。總之,道法自然,不自然的另一面通常是不正確,請(qǐng)注重培養(yǎng)這種編程嗅覺。”

    逗號(hào)使勁吸了吸鼻子。

    冒號(hào)遂作結(jié)語:“我們提倡針對(duì)接口編程programming to an interface),避免針對(duì)實(shí)現(xiàn)編程programming to an implementation)。以上三例則是通過接口深入實(shí)現(xiàn)programming through an interface to an implementation——《code complete》),本質(zhì)上正是針對(duì)實(shí)現(xiàn)編程。以違背服務(wù)初衷的方式享受的服務(wù),如同盛夏的豆腐——即使沒有變質(zhì),也是不能持久的。”

    posted on 2008-08-07 19:31 鄭暉 閱讀(2207) 評(píng)論(2)  編輯  收藏 所屬分類: 冒號(hào)和他的學(xué)生們

    評(píng)論

    # re: 冒號(hào)和他的學(xué)生們(連載27)——接口服務(wù) 2008-10-18 20:23 wanget

    很好的文章,看了一下午眼睛都疼了 ^_^

    問個(gè)問題,看到了你說的“除了盜版的商業(yè)軟件,都應(yīng)該能聯(lián)系到原作者“,如果公司里寫那段代碼的程序員走了,而代碼寫的又不規(guī)范,最要命的假如我本人需要維護(hù)那段代碼,而代碼又有好幾萬行……這種情況下有沒有什么好的思路呢? (C程序)  回復(fù)  更多評(píng)論   

    # re: 冒號(hào)和他的學(xué)生們(連載27)——接口服務(wù)[未登錄] 2008-10-19 12:49 鄭暉

    @wanget
    幾萬行的代碼在提交時(shí)竟然沒有明確規(guī)范的說明,此一錯(cuò);公司在代碼作者離職時(shí)沒有安排與接手人進(jìn)行必要的交接,此二錯(cuò);沒有留下作者的聯(lián)系方式,此三錯(cuò)。這一方面說明公司的管理不規(guī)范,另一方面也說明這部分代碼并不是那么重要,否則難以想象公司如何靠軟件開發(fā)來生存。維護(hù)這樣的代碼,首先要看這段代碼在整個(gè)系統(tǒng)或子系統(tǒng)中所扮演的角色,自己草擬一份規(guī)范說明,并與其他相關(guān)人員核實(shí)。(如果整個(gè)系統(tǒng)都沒有明確的規(guī)范的話,你得考慮跳槽了。)其次,找出所有這段代碼被外部調(diào)用的接口和公開變量(包括C程序中的全局變量)。最好不要依賴IDE,自己寫一段script來搜索并保留結(jié)果。這樣有兩個(gè)重要作用:一、通過客戶代碼反向推出接口的用法;二、在維護(hù)代碼時(shí)可以自由地改變其他的非接口部分,而無需擔(dān)心對(duì)其他部分代碼的影響。
      回復(fù)  更多評(píng)論   

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    博客搬家:http://blog.zhenghui.org
    《冒號(hào)課堂》一書于2009年10月上市,詳情請(qǐng)見
    冒號(hào)課堂

    留言簿(17)

    隨筆分類(61)

    隨筆檔案(61)

    文章分類(1)

    文章檔案(1)

    最新隨筆

    積分與排名

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 91亚洲国产成人久久精品| va亚洲va日韩不卡在线观看| 少妇人妻偷人精品免费视频| 三年片免费观看大全国语| 一个人看的www视频免费在线观看 一个人看的免费观看日本视频www | 亚洲综合日韩中文字幕v在线 | 国拍在线精品视频免费观看 | 国产日韩在线视频免费播放| 香蕉视频在线观看免费| 日本中文字幕免费看| 一级毛片在播放免费| 91av免费在线视频| 免费在线观影网站| 99视频免费观看| 精品国产无限资源免费观看| 免费观看AV片在线播放| 精品久久洲久久久久护士免费| 日本免费人成视频播放 | 亚洲视频免费观看| 美女视频黄的全免费视频| 最近免费中文字幕大全视频| 日本特黄特黄刺激大片免费| 成人亚洲网站www在线观看| 中文亚洲AV片在线观看不卡 | 免费在线不卡视频| 色噜噜AV亚洲色一区二区| 亚洲国产精品无码专区在线观看| 亚洲专区在线视频| 亚洲无人区码一二三码区别图片| 综合偷自拍亚洲乱中文字幕| a级毛片免费网站| 99re视频精品全部免费| 性感美女视频在线观看免费精品| 免费一看一级毛片| 亚洲国产精品嫩草影院在线观看| 亚洲日韩乱码中文无码蜜桃| 亚洲AV无码国产精品永久一区| 黄色视屏在线免费播放| 69视频免费观看l| 国产成人免费永久播放视频平台 | 好男人www免费高清视频在线|