OO經過這么多年的錘煉和考驗證明是極好的,雖然也有些的人提出一些反面的意見,證明時代在發展、進步大家需要更先進的設計方法,不過OO終歸是目前應用最為廣泛也最為適用的程序設計方法學。個人覺得適用最為重要,畢竟OO是能夠很好解決大多數復雜系統設計的。不過同時OO也讓設計者陷入一個兩難的境地。一來容易設計過輕,也就是設計的不夠,發揮不了OO的強大和精妙之處,面向過程和面向對象的夾雜反而使得實現者摸不著頭腦非常痛苦(很多時候這里指的設計者和實現著會是同一個人);二來容易設計過度,讓OO從一個手中的工具變成了一塊腳下的石頭,讓實現者工作起來異常的不順利,覺得做了很多脫了褲子放屁的事情(請容許我的粗魯,因為我再也找不到比這個更好的比喻了)。
要解決這些問題往往需要經驗的積累和技巧的總結,知道OO理論的人不少,真正在設計中運用的好的確實不多。當然OO設計中最最重要的一個部分就是繼承了,下面列舉一些常見的繼承設計技巧,讀過《Core Java》的人可能對它們非常熟悉,我結合我自己的理解做一些說明,也當作一個學習。當然不是記住了這些所謂的技巧就學會了繼承設計,總的來講設計是需要遵循一定規律、結合實際情況、發揮自己的經驗而做出的,還是需要自己多多總結和積累。
1. 將公共操作和域放置在超類 顯然這是繼承最基本的目的,減少編碼量,減少業務關注面。讓子類更多關注自己的業務實現,而公共的由共同的超類去操心。
2. 不要使用受保護的域 很多程序員其實都很喜歡“受保護的”(protected)這種作用域,特別是應用在域上,因為在這種作用域的作用下子類可以輕松的直接訪問超類中相應的域,可能也覺得這是理所當然的事情,因為既然在子類中繼承了這個域而不能直接使用它還需要使用super關鍵字來調用超類方法去訪問往往顯得很別扭和難看。但是protected機制會帶來很嚴重的安全問題,第一,因為子類集合是無限制的,任何人都可以由一個類派生出另外一個子類,并編寫代碼直接訪問protected的實例域,從而破壞封裝性;第二,在Java中同一個包中的所有類都可以訪問protected域,而不管它是否為這個類的子類。
所以推薦在盡可能的情況下把域設置為私有,不允許外部直接訪問甚至修改。但其實很多初學者,包括一些編程老手都沒辦法理解和接受這種做法。我個人認為如果OO失去了封裝性就好比失去了靈魂的空殼,沒有了什么意義,反而變成累贅而已。
3. 使用繼承實現is-a關系 如果拋開所謂的設計思想來看,實現繼承最基本的目的就是節省代碼量,并且很容易就做到。但這樣往往很多人會濫用繼承,純粹為了節約代碼而節約代碼,而沒有顧及超類與子類的關系導致在實現其他相關問題的時候帶來很多麻煩,反而會多寫很多代碼,撿了芝麻丟了西瓜。
繼承應該要遵循is-a關系,要判斷是否遵循了is-a關系也有個很簡單的辦法,就是你念出這么一句話:“子類”是個“超類”,看是否合理。例如有一個雇員(Employee)類繼承與人(Person),這個時候就有這樣的關系:雇員是個人,顯然是正確的。
4. 除非所有繼承的方法都有意義,否則不要繼承 當子類和超類之間遵循了is-a關系,但子類從超類繼承來的某些方法對于子類是沒有意義的,甚至是實現錯誤功能的,這個時候應該取消繼承關系,因為這相當的危險。或者可以選擇重新審視你的設計。
5. 在覆蓋方法的時候,不要改變預期的行為 結合上面4中的觀點,有些人可能會說這個很簡單,把意義不同的方法在子類中重寫,或者干脆什么也不做,也或者拋出一個異常不久解決了,so easy!其實這樣也是違背OO思想的,應該盡量保持覆蓋方法的預期行為,只可能因為各自的業務含義而改變實現方式,但是語義和行為是要保證的,就好像超類有個方法名字叫add是用來做加法的,但是你一定要極端的在子類中重寫了它,里面的代碼偷偷實現了一個減法,這種做法的危險我想很容易理解。為什么說是偷偷的,因為可能只有你知道這里是做了減法,或者說幾個星期后你自己都認為這個方法實現的是一個加法運算!
6. 使用多態,而非類型信息 很多時候需要判斷當前對象的類型來執行相應不同的方法,看下面的示例代碼:
1 if(x is of type 1)
2 action1(x);
3 else if(x is of type 2)
4 action2(x);
這個時候應該去考慮action1和action2是不是表示同一個概念,如果是就應該使用多態性來處理。這個時候應該定義一個方法放置在這兩個類的超類或者接口中,然后就可以調用
1 x.action();
讓語言提供的多態性自己去找應該調用那個類的方法來實現。是不是像極了某種模式:)
7. 不要過多的使用反射 個人覺得Java擁有了反射機制簡直就是太強大了,在運行時能夠查看甚至修改、調用域和方法極大的提高了程序實現的靈活性和技巧性。以至于我甚至有一段時間把Java當作JavaScript來玩(愛死JavaScript的靈活性但同樣具有那么優秀的OO)。看看現在大多數流行不流行的開發框架都是基于Java這種強大的能力來實現的,它讓大家可以編寫更加通用的程序,也是為什么它在系統程序(包括一些框架、工具甚至服務器等)中使用這么廣泛并都作為核心技術;但是在編寫應用程序的過程中應該減少反射的使用,因為反射其實是很脆弱的,編譯器很難幫助大家發現程序中的錯誤,任何錯誤都到了運行時才被發現,并導致一些莫名其妙的異常。說起莫名其妙其實不是說反射功能不夠健壯或有問題,而是出現錯誤后很難跟蹤和排查,給開發和維護帶來很大困難。
還有一點也很重要,反射比直接調用慢,這個要時刻記住。所以應該用接口來實現回調之類的功能而不是反射。
其實這些只是繼承技巧的冰山一角而已,每個人在設計過程中都會總結出自己的經驗。
總的來說我們應該用理論來指導實踐,而在實踐中總結出理論!
posted on 2007-04-12 01:51
cresposhi 閱讀(2087)
評論(12) 編輯 收藏