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

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

最大限制地提高代碼的可重用性

2019-11-18 11:45:52
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  克服傳統(tǒng)面向?qū)ο缶幊谭椒ㄔ诳芍赜眯苑矫娴牟蛔?
  
  摘要
  不要放棄編寫(xiě)可重用代碼的努力!本技巧總結(jié)了三種修改您的現(xiàn)有代碼以增強(qiáng)其可重用性的方法。
  作者:Jeff Mather
  重用是一種神話,這似乎正在日漸成為編程人員的一種共識(shí)。然而,重用可能難以實(shí)現(xiàn),因?yàn)閭鹘y(tǒng)面向?qū)ο缶幊谭椒ㄔ诳芍赜眯苑矫娲嬖谝恍┎蛔恪1炯记烧f(shuō)明了組成支持重用的一種不同方法的三個(gè)步驟。 
  第一步:將功能移出類實(shí)例方法
  由于類繼續(xù)機(jī)制缺乏精確性,因此對(duì)于代碼重用來(lái)說(shuō)它并不是一種最理想的機(jī)制。也就是說(shuō),假如您要重用某個(gè)類的單個(gè)方法,就必須繼續(xù)該類的其他方法以及數(shù)據(jù)成員。這種累贅不必要地將要重用此方法的代碼復(fù)雜化了。繼續(xù)類對(duì)其父類的依靠性引入了額外的復(fù)雜性:對(duì)父類的更改會(huì)影響子類;當(dāng)更改父類或子類中的任一方時(shí),很難記住覆蓋了哪些方法(或者沒(méi)有覆蓋哪些方法);而且是否應(yīng)該調(diào)用相應(yīng)的父類方法也不明朗。
  
  執(zhí)行單一概念性任務(wù)的任何方法都應(yīng)該是獨(dú)立的,并應(yīng)將其作為要重用的首選方法。要實(shí)現(xiàn)這一點(diǎn),我們必須返回到過(guò)程式編程,將代碼移出類實(shí)例方法并將其移入全局可見(jiàn)的過(guò)程中。為了提高這類過(guò)程的可重用性,您應(yīng)該像編寫(xiě)靜態(tài)實(shí)用方法那樣編寫(xiě)這類方法:每個(gè)過(guò)程只使用其自身的輸入?yún)?shù)和/或?qū)ζ渌挚梢?jiàn)過(guò)程的調(diào)用完成其工作,而且不應(yīng)該使用任何非局部變量。這種外部依靠性的減弱降低了使用該過(guò)程的復(fù)雜性,從而可促進(jìn)在別處對(duì)它的重用。當(dāng)然,即便那些不計(jì)劃重用的代碼也會(huì)從這種結(jié)構(gòu)中受益,因?yàn)樗慕Y(jié)構(gòu)總是相當(dāng)清楚。
  
  在 java 中,方法不能脫離類而存在。但是,您可以采取相關(guān)步驟,使方法成為單個(gè)類的、公共可見(jiàn)的靜態(tài)方法。作為示例,您可以采用類似下面這樣的一個(gè)類:
  
  class Polygon {
  .
  .
  public int getPerimeter() {...}
  public boolean isConvex() {...}
  public boolean containsPoint(Point p) {...}
  .
  .
  }
  
  并將其更改為類似以下的形式:
  
  class Polygon {
  .
  .
  public int getPerimeter() {return pPolygon.computePerimeter(this);}
  public boolean isConvex() {return pPolygon.isConvex(this);}
  public boolean containsPoint(Point p) {return pPolygon.containsPoint(this, p);}
  .
  .
  }
  
  其中,pPolygon 如下所示:
  
  class pPolygon {
  static public int computePerimeter(Polygon polygon) {...}
  static public boolean isConvex(Polygon polygon) {...}
  static public boolean containsPoint(Polygon polygon, Point p) {...}
  }
  
  類名 pPolygon 反映了該類所封裝的過(guò)程主要與類型 Polygon 的對(duì)象有關(guān)。類名前的 p 表示該類的唯一用途就是將公共可見(jiàn)的靜態(tài)過(guò)程組織起來(lái)。然而,在 Java 中類名以小寫(xiě)字母開(kāi)頭是不規(guī)范的,像 pPolygon 這樣的類并不完成正常的類功能。這就是說(shuō),它不代表一類對(duì)象;它只是該語(yǔ)言所需的一個(gè)組織實(shí)體。
  
  在以上事例中所作更改的全部效果就是,客戶端代碼不再非要通過(guò)繼續(xù) Polygon 來(lái)重用其功能。現(xiàn)在這一功能在 pPolygon 類中是以過(guò)程為單位提供的。客戶端代碼僅使用它所需的功能,而不必關(guān)心它不需要的功能。
  
  這并不意味著類不會(huì)在新的過(guò)程式編程風(fēng)格中發(fā)揮積極作用。恰恰相反,類要執(zhí)行必要的分組任務(wù),并封裝它們所代表的對(duì)象的數(shù)據(jù)成員。此外,類通過(guò)實(shí)現(xiàn)多個(gè)接口而具備的多態(tài)性使其具備了卓越的可重用性,請(qǐng)參閱第二步中的說(shuō)明。但是,您應(yīng)該將通過(guò)類繼續(xù)獲得可重用性和多態(tài)性的方法歸類到優(yōu)先級(jí)較低的技術(shù)中,因?yàn)閷⒐δ馨趯?shí)例方法中并不是實(shí)現(xiàn)可重用性的最佳選擇。
  
  四人合著的暢銷書(shū) Design Patterns 簡(jiǎn)要提及了一種與這一技術(shù)只有細(xì)微差別的技術(shù)。那本書(shū)中的 Strategy 模式提倡用一個(gè)共公接口將相關(guān)算法的每個(gè)系列成員都封裝起來(lái),以便客戶端代碼可互換?????這些算法。因?yàn)橐环N算法通常被編寫(xiě)為一個(gè)或幾個(gè)獨(dú)立的過(guò)程,因而這種封裝強(qiáng)調(diào)重用執(zhí)行單一任務(wù)(即一個(gè)算法)的過(guò)程,而不強(qiáng)調(diào)重用包含代碼和數(shù)據(jù)、執(zhí)行多項(xiàng)任務(wù)的對(duì)象。本步驟也體現(xiàn)了同樣的基本思想。
  
  然而,用接口封裝算法意味著將算法編寫(xiě)為實(shí)現(xiàn)該接口的一個(gè)對(duì)象。這意味著我們?nèi)匀槐皇`在與數(shù)據(jù)耦合在一起的過(guò)程及其封裝對(duì)象的其他方法上,因而使重用變得復(fù)雜。每次使用算法時(shí)必須實(shí)例化這些對(duì)象也是個(gè)問(wèn)題,這將降低程序的性能。幸運(yùn)的是, Design Patterns 提供的一種解決方案可解決這兩個(gè)問(wèn)題。在編寫(xiě) Strategy 對(duì)象時(shí)您可使用 Flyweight 模式,以使每個(gè)對(duì)象僅有一個(gè)眾所周知的共享實(shí)例(該實(shí)例處理執(zhí)行問(wèn)題),這樣每個(gè)共享對(duì)象就不會(huì)在兩次訪問(wèn)之間維護(hù)狀態(tài)(因此該對(duì)象不包含任何成員變量,從而解決了許多耦合問(wèn)題)。生成的 Flyweight-Strategy 模式將本步驟中封裝功能的技術(shù)高度集成在全局可用的無(wú)狀態(tài)過(guò)程中。
  
  第二步:將非基本數(shù)據(jù)類型的輸入?yún)?shù)類型轉(zhuǎn)換為接口類型
  通過(guò)接口參數(shù)類型而非通過(guò)類繼續(xù)利用多態(tài)性,這是在面向?qū)ο缶幊谭椒ㄖ袑?shí)現(xiàn)可重用性的真正基礎(chǔ),正如 Allen Holub 在 "Build User Interfaces for Object-Oriented Systems, Part 2" 中所講的那樣。
  
  “... 可重用性是通過(guò)編寫(xiě)接口,而不是通過(guò)編寫(xiě)類來(lái)實(shí)現(xiàn)的。假如一個(gè)方法的所有參數(shù)均為一些已知接口的引用,而這些接口又是由您從未聽(tīng)過(guò)的一些類實(shí)現(xiàn)的,那么該方法可對(duì)編寫(xiě)代碼時(shí)還不存在的類的對(duì)象進(jìn)行操作。從技術(shù)上講,可重用的是方法,而不是傳遞給該方法的對(duì)象。”
  將 Holub 的論述應(yīng)用到第一步的結(jié)果,一旦某個(gè)功能塊可作為一個(gè)全局可見(jiàn)的獨(dú)立過(guò)程,您就可以通過(guò)將它的每個(gè)類級(jí)輸入?yún)?shù)類型轉(zhuǎn)換為接口類型,從而進(jìn)一步提高它的可重用性。這樣,實(shí)現(xiàn)該接口類型的任何類的對(duì)象都符合該參數(shù)的要求,而不僅僅是符合原始類的要求。這樣,該過(guò)程便潛在地可用于更多的對(duì)象類型。
  
  例如,假定您有一個(gè)全局可見(jiàn)的靜態(tài)方法:
  
  static public boolean contains(Rectangle rect, int x, int y) {...}
  
  該方法旨在判定給定的矩形是否包含給定的位置。此處您應(yīng)該將 rect 參數(shù)的類型從類類型 Rectangle 更改為接口類型,如下所示:
  
  static public boolean contains(Rectangular rect, int x, int y) {...}
  
  Rectangular could be the following interface:
  
  public interface Rectangular {
  Rectangle getBounds();
  }
  
  現(xiàn)在,可描述為 Rectangular 的類(即可實(shí)現(xiàn) Rectangular 接口)的對(duì)象都可作為 rect 的參數(shù)傳遞給 PRectangular.contains()。我們通過(guò)放寬對(duì)可傳遞給方法的參數(shù)的約束來(lái)提高方法的可重用性。
  
  但是,就以上示例而言,當(dāng) Rectangle 接口的 getBounds 方法返回一個(gè) Rectangle 時(shí),您可能不知道使用 Rectangular 接口會(huì)有什么實(shí)際的好處;也就是說(shuō),假如我們知道我們要傳入的對(duì)象在被請(qǐng)求時(shí)能返回 Rectangle;為什么不傳入 Rectangle 類型而要傳入接口類型呢?最重要的原因與集合有關(guān)。假定有這樣一個(gè)方法:
  
  static public boolean areAnyOverlapping(Collection rects) {...}
  
  該方法旨在判定給定集合中的 rectangular 對(duì)象是否有重疊。接下來(lái),在方法體中,當(dāng)您依次處理集合中的每個(gè)對(duì)象時(shí),假如無(wú)法將對(duì)象轉(zhuǎn)換為諸如 Rectangular 這樣的接口類型,如何才能訪問(wèn)那個(gè)對(duì)象的 rectangle 呢?唯一的選擇是將對(duì)象轉(zhuǎn)換為特定的類類型(我們已知該類中有一個(gè)方法能提供 rectangle),這意味著該方法必須事先知道它要對(duì)何種類類型進(jìn)行操作,因此重用它時(shí)只能使用這些類型。這就是這一步首先要避免的問(wèn)題!
  
  第三步:選擇耦合性較小的輸入?yún)?shù)接口類型
  在執(zhí)行第二步時(shí),應(yīng)該選擇何種接口類型來(lái)替代給定的類類型呢?答案是:能充分描述過(guò)程對(duì)參數(shù)的要求且累贅最少的任何接口。參數(shù)對(duì)象要實(shí)現(xiàn)的接口越小,任一特定類能實(shí)現(xiàn)該接口的機(jī)會(huì)就越大 -- 因而其對(duì)象可用作該參數(shù)的類的數(shù)量也就越多。很輕易看出,假如您有如下這樣一個(gè)方法:
  
  static public boolean areOverlapping(Window window1, Window window2) {...}
  
  該方法旨在判定兩個(gè)(假定為 rectangular)窗口是否重疊,假如該方法僅要求它的兩個(gè)參數(shù)提供它們各自的 rectangular 坐標(biāo),則最好簡(jiǎn)化這兩個(gè)參數(shù)的類型以反映這一事實(shí):
  
  static public boolean areOverlapping(Rectangular rect1, Rectangular rect2) {...}
  
  以上代碼假定前面的 Window 類型對(duì)象也能實(shí)現(xiàn) Rectangular。現(xiàn)在您就可以重用任何 rectangular 對(duì)象的第一個(gè)方法中所包含的功能。
  
  您可能有過(guò)多次這樣的經(jīng)歷,即充分指定了參數(shù)要求的可用接口包含過(guò)多不必要的方法。碰到這種情況時(shí),您就應(yīng)在全局名稱空間中定義一個(gè)新的公共接口,以便其他可能面臨同樣窘境的方法重用這個(gè)接口。
  
  您也可能有過(guò)多次這樣的經(jīng)歷,即最好創(chuàng)建一個(gè)獨(dú)特的接口來(lái)指定單個(gè)過(guò)程對(duì)一個(gè)參數(shù)的要求。您所創(chuàng)建的接口只會(huì)用于那個(gè)參數(shù)。當(dāng)您希望將參數(shù)當(dāng)作 C 中的函數(shù)指針處理時(shí)經(jīng)常會(huì)出現(xiàn)這種情況,例如,假定有這樣一個(gè)過(guò)程:
  
  static public void sort(List list, SortComparison comp) {...}
  
  該過(guò)程通過(guò)使用給定的比較對(duì)象 comp 對(duì)列表的所有對(duì)象進(jìn)行比較,從而對(duì)給定的列表進(jìn)行排序,sort 對(duì) comp 的全部要求就是調(diào)用其單個(gè)方法執(zhí)行比較。因此,SortCo

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 青田县| 浪卡子县| 麻栗坡县| 红河县| 外汇| 阳城县| 邯郸县| 九龙县| 德兴市| 芮城县| 启东市| 虹口区| 成都市| 德钦县| 高青县| 齐齐哈尔市| 仪陇县| 苍溪县| 黑山县| 边坝县| 定州市| 衡南县| 平乡县| 清远市| 鹿泉市| 绥宁县| 罗山县| 厦门市| 滦平县| 榆中县| 肇源县| 余庆县| 北流市| 南乐县| 怀远县| 琼结县| 西藏| 大新县| 高碑店市| 溆浦县| 东乌|