隨筆 - 81  文章 - 1033  trackbacks - 0
          <2007年4月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          在浮躁的年代里,我們進(jìn)取心太切,患得患失;虛榮心太強(qiáng),戰(zhàn)戰(zhàn)兢兢。一心爭(zhēng)強(qiáng)好勝,惟恐榜上無(wú)名。
          I think I can fly , and flying like a bird !
          程序員一名,已售出,缺貨中!

          我的郵件聯(lián)系方式

          用且僅用于MSN

          博客點(diǎn)擊率
          free web counter
          free web counter

          常用鏈接

          留言簿(36)

          隨筆檔案

          搜索

          •  

          積分與排名

          • 積分 - 187343
          • 排名 - 309

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜


                OO經(jīng)過(guò)這么多年的錘煉和考驗(yàn)證明是極好的,雖然也有些的人提出一些反面的意見(jiàn),證明時(shí)代在發(fā)展、進(jìn)步大家需要更先進(jìn)的設(shè)計(jì)方法,不過(guò)OO終歸是目前應(yīng)用最為廣泛也最為適用的程序設(shè)計(jì)方法學(xué)。個(gè)人覺(jué)得適用最為重要,畢竟OO是能夠很好解決大多數(shù)復(fù)雜系統(tǒng)設(shè)計(jì)的。不過(guò)同時(shí)OO也讓設(shè)計(jì)者陷入一個(gè)兩難的境地。一來(lái)容易設(shè)計(jì)過(guò)輕,也就是設(shè)計(jì)的不夠,發(fā)揮不了OO的強(qiáng)大和精妙之處,面向過(guò)程和面向?qū)ο蟮膴A雜反而使得實(shí)現(xiàn)者摸不著頭腦非常痛苦(很多時(shí)候這里指的設(shè)計(jì)者和實(shí)現(xiàn)著會(huì)是同一個(gè)人);二來(lái)容易設(shè)計(jì)過(guò)度,讓OO從一個(gè)手中的工具變成了一塊腳下的石頭,讓實(shí)現(xiàn)者工作起來(lái)異常的不順利,覺(jué)得做了很多脫了褲子放屁的事情(請(qǐng)容許我的粗魯,因?yàn)槲以僖舱也坏奖冗@個(gè)更好的比喻了)。

                要解決這些問(wèn)題往往需要經(jīng)驗(yàn)的積累和技巧的總結(jié),知道OO理論的人不少,真正在設(shè)計(jì)中運(yùn)用的好的確實(shí)不多。當(dāng)然OO設(shè)計(jì)中最最重要的一個(gè)部分就是繼承了,下面列舉一些常見(jiàn)的繼承設(shè)計(jì)技巧,讀過(guò)《Core Java》的人可能對(duì)它們非常熟悉,我結(jié)合我自己的理解做一些說(shuō)明,也當(dāng)作一個(gè)學(xué)習(xí)。當(dāng)然不是記住了這些所謂的技巧就學(xué)會(huì)了繼承設(shè)計(jì),總的來(lái)講設(shè)計(jì)是需要遵循一定規(guī)律、結(jié)合實(shí)際情況、發(fā)揮自己的經(jīng)驗(yàn)而做出的,還是需要自己多多總結(jié)和積累。

          1.  將公共操作和域放置在超類(lèi)

                顯然這是繼承最基本的目的,減少編碼量,減少業(yè)務(wù)關(guān)注面。讓子類(lèi)更多關(guān)注自己的業(yè)務(wù)實(shí)現(xiàn),而公共的由共同的超類(lèi)去操心。


          2.  不要使用受保護(hù)的域

                很多程序員其實(shí)都很喜歡“受保護(hù)的”(protected)這種作用域,特別是應(yīng)用在域上,因?yàn)樵谶@種作用域的作用下子類(lèi)可以輕松的直接訪問(wèn)超類(lèi)中相應(yīng)的域,可能也覺(jué)得這是理所當(dāng)然的事情,因?yàn)榧热辉谧宇?lèi)中繼承了這個(gè)域而不能直接使用它還需要使用super關(guān)鍵字來(lái)調(diào)用超類(lèi)方法去訪問(wèn)往往顯得很別扭和難看。但是protected機(jī)制會(huì)帶來(lái)很?chē)?yán)重的安全問(wèn)題,第一,因?yàn)樽宇?lèi)集合是無(wú)限制的,任何人都可以由一個(gè)類(lèi)派生出另外一個(gè)子類(lèi),并編寫(xiě)代碼直接訪問(wèn)protected的實(shí)例域,從而破壞封裝性;第二,在Java中同一個(gè)包中的所有類(lèi)都可以訪問(wèn)protected域,而不管它是否為這個(gè)類(lèi)的子類(lèi)。

                所以推薦在盡可能的情況下把域設(shè)置為私有,不允許外部直接訪問(wèn)甚至修改。但其實(shí)很多初學(xué)者,包括一些編程老手都沒(méi)辦法理解和接受這種做法。我個(gè)人認(rèn)為如果OO失去了封裝性就好比失去了靈魂的空殼,沒(méi)有了什么意義,反而變成累贅而已。


          3.  使用繼承實(shí)現(xiàn)is-a關(guān)系

                如果拋開(kāi)所謂的設(shè)計(jì)思想來(lái)看,實(shí)現(xiàn)繼承最基本的目的就是節(jié)省代碼量,并且很容易就做到。但這樣往往很多人會(huì)濫用繼承,純粹為了節(jié)約代碼而節(jié)約代碼,而沒(méi)有顧及超類(lèi)與子類(lèi)的關(guān)系導(dǎo)致在實(shí)現(xiàn)其他相關(guān)問(wèn)題的時(shí)候帶來(lái)很多麻煩,反而會(huì)多寫(xiě)很多代碼,撿了芝麻丟了西瓜。

                繼承應(yīng)該要遵循is-a關(guān)系,要判斷是否遵循了is-a關(guān)系也有個(gè)很簡(jiǎn)單的辦法,就是你念出這么一句話(huà):“子類(lèi)”是個(gè)“超類(lèi)”,看是否合理。例如有一個(gè)雇員(Employee)類(lèi)繼承與人(Person),這個(gè)時(shí)候就有這樣的關(guān)系:雇員是個(gè)人,顯然是正確的。


          4.  除非所有繼承的方法都有意義,否則不要繼承

                當(dāng)子類(lèi)和超類(lèi)之間遵循了is-a關(guān)系,但子類(lèi)從超類(lèi)繼承來(lái)的某些方法對(duì)于子類(lèi)是沒(méi)有意義的,甚至是實(shí)現(xiàn)錯(cuò)誤功能的,這個(gè)時(shí)候應(yīng)該取消繼承關(guān)系,因?yàn)檫@相當(dāng)?shù)奈kU(xiǎn)。或者可以選擇重新審視你的設(shè)計(jì)。


          5.  在覆蓋方法的時(shí)候,不要改變預(yù)期的行為

                結(jié)合上面4中的觀點(diǎn),有些人可能會(huì)說(shuō)這個(gè)很簡(jiǎn)單,把意義不同的方法在子類(lèi)中重寫(xiě),或者干脆什么也不做,也或者拋出一個(gè)異常不久解決了,so easy!其實(shí)這樣也是違背OO思想的,應(yīng)該盡量保持覆蓋方法的預(yù)期行為,只可能因?yàn)楦髯缘臉I(yè)務(wù)含義而改變實(shí)現(xiàn)方式,但是語(yǔ)義和行為是要保證的,就好像超類(lèi)有個(gè)方法名字叫add是用來(lái)做加法的,但是你一定要極端的在子類(lèi)中重寫(xiě)了它,里面的代碼偷偷實(shí)現(xiàn)了一個(gè)減法,這種做法的危險(xiǎn)我想很容易理解。為什么說(shuō)是偷偷的,因?yàn)榭赡苤挥心阒肋@里是做了減法,或者說(shuō)幾個(gè)星期后你自己都認(rèn)為這個(gè)方法實(shí)現(xiàn)的是一個(gè)加法運(yùn)算!


          6.  使用多態(tài),而非類(lèi)型信息

                很多時(shí)候需要判斷當(dāng)前對(duì)象的類(lèi)型來(lái)執(zhí)行相應(yīng)不同的方法,看下面的示例代碼:

          1 if(x is of type 1)
          2   action1(x);
          3 else if(x is of type 2)
          4   action2(x);

                這個(gè)時(shí)候應(yīng)該去考慮action1和action2是不是表示同一個(gè)概念,如果是就應(yīng)該使用多態(tài)性來(lái)處理。這個(gè)時(shí)候應(yīng)該定義一個(gè)方法放置在這兩個(gè)類(lèi)的超類(lèi)或者接口中,然后就可以調(diào)用

          1 x.action();

                讓語(yǔ)言提供的多態(tài)性自己去找應(yīng)該調(diào)用那個(gè)類(lèi)的方法來(lái)實(shí)現(xiàn)。是不是像極了某種模式:)


          7.  不要過(guò)多的使用反射

                個(gè)人覺(jué)得Java擁有了反射機(jī)制簡(jiǎn)直就是太強(qiáng)大了,在運(yùn)行時(shí)能夠查看甚至修改、調(diào)用域和方法極大的提高了程序?qū)崿F(xiàn)的靈活性和技巧性。以至于我甚至有一段時(shí)間把Java當(dāng)作JavaScript來(lái)玩(愛(ài)死JavaScript的靈活性但同樣具有那么優(yōu)秀的OO)。看看現(xiàn)在大多數(shù)流行不流行的開(kāi)發(fā)框架都是基于Java這種強(qiáng)大的能力來(lái)實(shí)現(xiàn)的,它讓大家可以編寫(xiě)更加通用的程序,也是為什么它在系統(tǒng)程序(包括一些框架、工具甚至服務(wù)器等)中使用這么廣泛并都作為核心技術(shù);但是在編寫(xiě)應(yīng)用程序的過(guò)程中應(yīng)該減少反射的使用,因?yàn)榉瓷淦鋵?shí)是很脆弱的,編譯器很難幫助大家發(fā)現(xiàn)程序中的錯(cuò)誤,任何錯(cuò)誤都到了運(yùn)行時(shí)才被發(fā)現(xiàn),并導(dǎo)致一些莫名其妙的異常。說(shuō)起莫名其妙其實(shí)不是說(shuō)反射功能不夠健壯或有問(wèn)題,而是出現(xiàn)錯(cuò)誤后很難跟蹤和排查,給開(kāi)發(fā)和維護(hù)帶來(lái)很大困難。

                還有一點(diǎn)也很重要,反射比直接調(diào)用慢,這個(gè)要時(shí)刻記住。所以應(yīng)該用接口來(lái)實(shí)現(xiàn)回調(diào)之類(lèi)的功能而不是反射。




                其實(shí)這些只是繼承技巧的冰山一角而已,每個(gè)人在設(shè)計(jì)過(guò)程中都會(huì)總結(jié)出自己的經(jīng)驗(yàn)。

                總的來(lái)說(shuō)我們應(yīng)該用理論來(lái)指導(dǎo)實(shí)踐,而在實(shí)踐中總結(jié)出理論!
          posted on 2007-04-12 01:51 cresposhi 閱讀(2093) 評(píng)論(12)  編輯  收藏

          FeedBack:
          # re: Core Java之OO繼承設(shè)計(jì)技巧[未登錄](méi) 2007-04-12 08:57 阿蜜果
          總結(jié)得不錯(cuò)!  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 10:18 BeanSoft
          兄弟改行做培訓(xùn)吧....  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 10:21 cresposhi
          我也有這種想法啊。。。
          我們來(lái)搞個(gè)業(yè)界領(lǐng)先的Java培訓(xùn)機(jī)構(gòu)列,呵呵  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 10:23 劉甘泉
          繼承會(huì)造成基類(lèi)的脆弱性,所以能不用繼承最好不用。。。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 10:30 cresposhi
          @劉甘泉
          不用繼承用接口嗎?我這里不單指Java中的概念
          請(qǐng)甘泉兄指教  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 10:50 junglesong
          >>不要使用受保護(hù)的域?

          這句話(huà)應(yīng)該改寫(xiě)為"如果一個(gè)成員不是為了繼承而設(shè)計(jì),不要使用protected而使用private".


          <<代碼大全2>>中的關(guān)于類(lèi)質(zhì)量的觀點(diǎn)也值得推薦:
          硬性規(guī)定:
          1.類(lèi)層次不宜超過(guò)三層.
          2.類(lèi)成員數(shù)量不宜超過(guò)7個(gè),如果全是簡(jiǎn)單數(shù)據(jù)類(lèi)型最多9個(gè),有其它類(lèi)的話(huà)限制為5個(gè),否則需要分解成更小的類(lèi).
          3.避免創(chuàng)建萬(wàn)能類(lèi)
          4.消除不必要的成員.
          5.消除無(wú)關(guān)精要的類(lèi).
          6.避免用動(dòng)詞命名類(lèi).

          抽象:
          1.類(lèi)是否有一個(gè)中心目的.
          2.類(lèi)的命名是否表現(xiàn)了其中心目的.
          3.類(lèi)的接口是否展現(xiàn)了一致的抽象.
          4.類(lèi)的接口是否讓人明白了知道該如何使用它.
          5.類(lèi)的接口是否足夠抽象,使使用者不必顧慮它是如何進(jìn)行服務(wù)的.
          6.類(lèi)提供的服務(wù)是否足夠完整,能讓其它類(lèi)無(wú)須動(dòng)用其內(nèi)部數(shù)據(jù).
          7.是否已經(jīng)盡量分解.
          8.在修改類(lèi)是是否維持了接口的完整性.

          封裝:
          1.是否把類(lèi)成員的可訪問(wèn)性降至最小.
          2.是否避免暴露類(lèi)中的數(shù)據(jù)成員.
          3.類(lèi)是否已經(jīng)盡可能的對(duì)其它類(lèi)隱藏了實(shí)現(xiàn)細(xì)節(jié).
          4.類(lèi)是否不依賴(lài)其它類(lèi),它是松耦合的嗎?

          http://junglesong.yculblog.com  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 11:26 cresposhi
          @junglesong
          我覺(jué)得即使是為了繼承而設(shè)計(jì),也不應(yīng)該使用protected。原因是因?yàn)榧热欢x在超類(lèi)中的域,它的訪問(wèn)規(guī)則應(yīng)該由超類(lèi)來(lái)關(guān)心和處理,不應(yīng)該授權(quán)給子類(lèi)直接干涉,這樣既破壞了封裝性也不利于維護(hù)。
          特別是protected作用域還可以本包訪問(wèn),這樣就給了更多其他對(duì)象修改本類(lèi)對(duì)象狀態(tài)的機(jī)會(huì),相當(dāng)危險(xiǎn)。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 14:43 kirari_wxy
          模式應(yīng)用有很多矛盾的地方,度的把握很難,不過(guò)四人幫的設(shè)計(jì)模式還是經(jīng)典的。關(guān)于類(lèi)庫(kù)的設(shè)計(jì)我個(gè)人比較欣賞只有樹(shù)葉才是實(shí)現(xiàn)類(lèi)的做法,其他都是接口和抽象類(lèi),至少ocp是最基礎(chǔ)的一條。protected應(yīng)該去掉。。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-12 22:59 軒朗=maninred
          《Core Java》中提到的OO設(shè)計(jì)思想并不多,更多的是對(duì)JDK中的API的示例。關(guān)于OO的設(shè)計(jì)思想建議你看看Robert C.Martin《敏捷軟件開(kāi)發(fā)》,書(shū)中提到的OO設(shè)計(jì)原則是經(jīng)過(guò)了多年業(yè)界OO實(shí)踐得到的。《Core Java》中的代碼用來(lái)練習(xí)重構(gòu)手法還差不多。

          這篇文章開(kāi)頭說(shuō)到的OO過(guò)度設(shè)計(jì)和OO不足其實(shí)用K.Back的TDD就可以比較好的解決。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-13 12:41 cresposhi
          TDD?倒是一直都沒(méi)機(jī)會(huì)真正領(lǐng)略它的風(fēng)采。。。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-04-13 12:43 cresposhi
          @軒朗=maninred
          《Core Java》確實(shí)不是一本專(zhuān)門(mén)講OO的書(shū)。。。只是看到作者總結(jié)的這么幾點(diǎn)自己的心得覺(jué)得比較通用和好用,所以拿來(lái)分析一把
          要真正了解OO設(shè)計(jì)方法確實(shí)要寫(xiě)好幾本數(shù)。。。  回復(fù)  更多評(píng)論
            
          # re: Core Java之OO繼承設(shè)計(jì)技巧 2007-05-08 19:56 咖啡屋的鼠標(biāo)
          個(gè)人認(rèn)為抽象類(lèi)才是為繼承而設(shè)計(jì)的,普通類(lèi)不是。而能用接口的盡量還是不使用抽象類(lèi)。
          >>>>>>
          最近發(fā)現(xiàn)TDD很容易造成設(shè)計(jì)欠賬,相對(duì)與過(guò)度設(shè)計(jì),設(shè)計(jì)欠賬也是不好的。想要用好TDD還得修煉啊。  回復(fù)  更多評(píng)論
            

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 嵊州市| 康平县| 宣城市| 吴川市| 廉江市| 滦平县| 金门县| 惠州市| 康乐县| 抚顺市| 罗平县| 涞源县| 盘山县| 公主岭市| 白城市| 扎鲁特旗| 汉沽区| 太康县| 兴和县| 定兴县| 鹿泉市| 从化市| 涟水县| 沙湾县| 小金县| 苏尼特右旗| 深圳市| 新民市| 贵港市| 沧州市| 灌阳县| 和政县| 嘉定区| 石屏县| 苗栗县| 原平市| 泰宁县| 张家港市| 武胜县| 英超| 东丽区|