国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

試簡單概括面向對象接口編程

2019-11-18 12:03:14
字體:
來源:轉載
供稿:網友

  本文不是為了論證面向對象方法論。那需要深厚的理論知識和豐富的實踐經驗。本人兩方面都差得很遠。
  這里只是試圖給出一個對面象接口的深入淺出的簡單原則。
  就象數學很難,數論很難,但是九九表不難,各位數字之和被3整除推出這個整數能被3整除也不難。(但是,兩者都很有用)
  
  其實,總感覺oo被多數人都誤解了。Fp世界的人一說oo,必然就拿出oo的類呀,繼續啊,來和fp比較一番。多態被他們理解為在繼續中的一種定制(也就是override了)
  
  而oo世界中的人呢,有的也是抱著類,繼續不放。增量設計是他們的圣經。有的則是捧著一本本經典的面向對象著作念經,什么design pattern拉,refactoring啦,OO software constrUCtion啦,孜孜不倦地一個一個原則,一個一個定義,一個一個模式地反復辨析。所謂讀書破萬卷,下筆如有神啊。書上很多微言大義被反復引用,到處套用,但是有時候卻總是看上去不是那么回事。同一句話可以被兩個人引用卻得到不同的結論。就象都是讀新約的Christian,卻搞出了天主教,新教等等互指為異端的教派。到底是書錯了?還是讀書的人錯了?
  
  個人最討厭故弄玄虛,把簡單的事情搞復雜。這里,讓我試試能不能簡單地解釋一下面向接口這個oo原則。
  
  任何軟件都是由各種不同的模塊組成的(沒錯,最小的軟件,如一個hello world, 也是)
  從自頂向下的觀點看,一個大模塊由若干個小模塊組成,一個小模塊又由若干個更小的模塊組成。就象大樓由磚造成,磚由分子組成,分子由原子組成一樣。
  
  這些模塊之間不可能是互相獨立的,相互之間肯定要有各種關系。
  
  這些關系可以被總結為簡單的兩種:
  需求和服務。
  “需求”就是我要求別人給我提供什么樣功能的服務。
  “服務”就是我提供一個什么樣功能的服務。
  
  所有的關系,都是這樣兩個原子關系的組合。
  當設計任何一個模塊的時候,你所看見的就只應該是這個模塊對外界的需求和要提供的服務。你不應該看見隔著十萬八千里的模塊乙,也不應該看到容器或者配置文件是如何把模塊們(包括你現在設計的模塊)組裝起來的。那些,都屬于另外一個維度,另外一個和你不相交的宇宙空間的事。
  
  一些c++同志喜歡二分法,軟件在他們那里變成一個簡單的庫-用戶這樣的結構。在他們看來,庫可以任意復雜,只要給用戶提供一個簡單的接口就夠了。
  他們沒有看到,所謂的“庫-用戶”的劃分是相對的而不是絕對的。一個模塊提供一定的功能,那么它相對于使用它的功能的模塊就是一個“庫”,而這個模塊可能還要別人提供一些功能,那么象對于提供這些服務的模塊,它又是“用戶”。
  
  兩個模塊,很又可能互相都是用戶,也都是庫。(只不過相對于不同的服務層面,不同的維度而已)
  
  這樣的服務/需求的關系遍布于軟件的各個地方。
  而所謂oo, 面向接口,就是用來治理這些依靠關系的。
  就象你整理自己的計算機網絡布線或者電視機后面的各種顏色的線一樣,oo也就是一套行之有效的整理這些關系,讓它們不要變成一團亂麻的經驗之談。
  
  任何一個理論系統,要想美麗,就要遵循下面的準則:
  1.完整
  2.自恰
  3.簡單
  
  比如幾何學,用了幾條最簡單的,互相不相關的(所謂“正交”是也)的公理,組建出了一個宏偉的大廈。
  
  面向對象的設計原則也應該如此。我試著給出下面兩個公理,讓我們看看能不能
  1.完整地描述面向對象方法。
  2.不自相矛盾。
  3.簡單。
  
  原則A:需求者只要求自己需要的,ask no more, ask no less!
  原則B:服務者只提供最小的能夠提供足夠功能的界面, PRomise no more, promise no less!
  
  從這兩個原則,我們試著推演一下其它的許多oo的準則來。
  
  1.Ioc原則,或者dip原則。所謂具體依靠抽象,抽象不依靠具體。這是關于需求者的一個設計方法。
  碰到一個需要的功能,這個功能的實現實際上和我自己模塊的實現不相關,正交,所以我定義一個接口,從外界注射進來一個實現。
  
  那么,用原則A是怎么得到這個準則的呢?
  首先,ask no less, 所以假如功能不是和我正交的,那么僅僅定義一個接口從外界注射進來對我就不夠。不符合no less。比如,我的實現碰巧讓我需要一個InputStreamReader,而不能是StringReader,那么,假如僅僅從外界注射進來一個Reader,對我的實現來說,它達不到我的要求。
  所以,根據no less, ioc進來的需要是和當前模塊實現正交的。
  
  然后,no more,假如我不用ioc,直接自己new一個FileReader如何?本來只需要InputStreamReader, 你卻要求它的子類型FileReader? 明顯違反了no more的要求。
  
  再舉個例子,ioc要求不要new,而是從外界注射。那么是不是說我們就永遠不能new呢?永遠都不能X.instance()呢?
  當然不是。注重,我們的前提是正交,是no less。
  
  假如,我有一個抽象工廠:
  
  java代碼: 
  
  1 interface PersistenceFactory{
  ...}
   2  Persistence create();
   3 }
  
  那么,當實現這個工廠的jdbc實現的時候,很可能是這樣:
  java代碼: 
  
  1 class JdbcPersistenceFactory{
  ...}
  2  Persistence create(){
  ...}
   3   Return JdbcPersistence.instance();
   4  }
   5 }
  
  這里,你用了一個靜態工廠,直接依靠于JdbcPersistence實現類了。是不是違反了ioc規則呢?
  當然不是,請注重,我們的模塊本身就是實現JdbcPersistence的,那么,從外界再ioc一個PersistenceFactory或者Persistence就不符合正交,no less的要求了。
  
  而且,其實從常識就可以看出來,你JdbcPersistenceFactory的任務就是生成一個關于jdbc的PersistenceFactory。你假如自己不做,再ioc進來,這層層推諉,真正的工作誰做呢?
  
  2.Lsp。所謂任何地方假如你期待的是一個父類型Base,那么把它替換成任何的子類型Derived1, Derived2,程序都能正常工作。
  還是關于需求者的。假如你做到了ask no more,比如說你只需要Base提供的功能,就不要在接口上要求Derived1, Derived2,如此,我們自然可以任意替換實際的實現。
  假如你做到了ask no less,需要InputStreamReader就直接要求InputStreamReader而不是Reader,你就不會需要在代碼中做downcast到InputStreamReader的動作。也就不會出現把Reader替換成StringReader之后出現的運行時錯誤。
  
  3.單一職責原則。一個模塊只應該做一件事。
  仍然是需求者的設計方法。這里的“事”的概念應該是一個正交于其它“事”的功能。兩個互相緊密耦合的“事”其實是一件事。
  根據ask no more,假如一個模塊做了兩件正交的事,也就是把兩個正交的模塊耦合在一起,就意味著在我這個濫模塊的某個地方有從一個模塊到另一個模塊的不正當的需求。你要求了你不應該要求的。
  
  4。Ocp。開閉原則。軟件,模塊應該是可以不用改動代碼而被擴展的。
  其實,ocp與其說是一個原則,不如說是一個理想。它并沒有指出具體的可操作方法,而只是給了一個目標。
  一些人認為這就意味著類可以繼續。這個看法太狹隘了。擴展一個模塊固然可以用繼續和override,但是,用接口組合一樣可以做到。要害是,假如你的模塊依靠抽象的接口而不是具體的類,那么別人就可以很輕易通過接口組合,adapter, decorator什么的通過給你傳遞不同的接口實現而達到擴展的目的。
  這里面,仍然是一個簡單的ask no more在起作用。
  
  總而言之,所謂面向接口,對需求者來說,就是:用接口定義好自己需要的功能,no more, no less。而所謂“多態”,就是用來實現接口用的工具而已。
  完了。
  
  以上都是關于需求者的,那也是面向接口的主要方面。那么如何約束服務者呢?
  
  封裝啊。封裝實際上完全是給服務提供者的工具。你可以用它來隱藏自己的實現細節,通過最小化對客戶的服務承諾來得到最大的設計彈性。
  你要寫一個BankAccount,是否要公開所有的內部成員呢?一般可能都不是吧?
  對于這些服務的提供者,假如公開了數據成員,那么對用戶的account.balance = 100;這種動作,你沒有任何彈性,只能老老實實地做field update。
  相比于setBalance(),后者可以自由地在內部做trace啦,或者把職責轉交給內部類啦,等等等等。靈活得多。
  
  那么,為什么后者靈活呢?因為用方法封裝了field之后,我們promise的東西少了。我不對客戶承諾:“我肯定修改我的balance成員變量”,而是簡單地說:“我肯定會修改那個邏輯上的balance,你再getBalance()就可以得到這個新的值”。至于我是不是物理上內部有一個balance變量,是不是setBalance()就直接去修改這個變量,對不起,無可奉告。我可能沒有,也可能有。可能今天沒有明天有,也可能今天有,明天一重構就沒有了。
  
  兩者其實都達到了用戶的需求。但是后者明顯沒有承諾不必要承諾的實現細節。所以根據promise no more的原則,封裝后比封裝前好。
  
  下面再嘮叨一遍靜態工廠。
  
  對于類
  java代碼: 
  
  1 class X implements I{
  ...}
   2  public X(){…}
   3  public static I instance(){return new X();}
   4 }
  
  下面兩個方法都各自對服務做了什么承諾呢?
  jav

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 科技| 包头市| 灌云县| 清镇市| 昌图县| 阳信县| 同江市| 土默特右旗| 扶余县| 沙坪坝区| 金华市| 施甸县| 三原县| 陕西省| 玛曲县| 灵石县| 梨树县| 文安县| 东丽区| 小金县| 林州市| 湖口县| 且末县| 新郑市| 河西区| 嵊州市| 睢宁县| 云南省| 浙江省| 宁远县| 楚雄市| 万盛区| 孝感市| 报价| 甘肃省| 穆棱市| 绥阳县| 安宁市| 江川县| 雷山县| 汉阴县|