WEB开发网      婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈功缁犻箖鏌嶈閸撴氨鎹㈠☉娆愬闁告劕寮堕幖鎰棯閸撗勫殌闁宠鍨块幃鈺冣偓鍦Т椤ユ繈姊哄Ч鍥р偓妤呭磻閹捐桅闁告洦鍨扮粻娑㈡煕椤愶絾绀冩い搴$Ч濮婅櫣绮欏▎鎯у壋闂佸摜濮甸崝娆愪繆閻㈢ǹ绀嬫い鏍ㄨ壘閸炪劑姊洪棃娴ゆ稒鎷呴幓鎺嶅闂佸湱鍎ら〃鍡涘煕閹烘鐓曢柡鍥ュ妼娴滄粍銇勮箛锝呭籍闁哄备鈧磭鏆嗛悗锝庡墰閺嗙娀鏌ф导娆戝埌闁靛棙甯掗~婵嬫偂鎼达絼鐢荤紓浣诡殕閸ㄥ灝顫忕紒妯诲缂佹稑顑呭▓顓炩攽椤旀枻鍏紒鐘虫崌閵嗕礁顫濋幇浣光枌婵犵數濮崑鎾趁归敐鍥┿€婇柡鈧禒瀣厽婵☆垱顑欓崵瀣偓瑙勬偠閸庤精鐏冮梺缁樏鍫曞疮閻愮數纾奸柛灞炬皑鏁堥悗瑙勬礃缁繘藝鐎靛摜妫柟顖嗕礁浠悗娈垮枛閻栫厧鐣烽悡搴樻婵☆垯璀﹂悗宕囩磽閸屾瑧鍔嶆い銊ユ閻f繈骞栨担姝屾憰闂佺粯妫冮ˉ鎾诲汲鐎n喗鐓熸俊銈傚亾闁绘妫楅埢鎾澄旈崨顔规嫼闁荤姴娲犻埀顒冩珪閻忊偓闂備礁鎼幊鎰叏閹绢喗鍋╅柣銈庡灛娴滃綊鏌熼悜妯肩畺闁哄懏绻堝娲濞戞艾顣哄┑鈽嗗亝閻熲晠銆佸▎鎺旂杸闁哄啫鍊婚惁鍫ユ⒑濮瑰洤鐏叉繛浣冲嫮顩烽柨鏇炲€归悡鏇㈡煏婵炲灝鍔ら柛鈺嬬稻椤ㄣ儵鎮欓弶鎴濐潚濡ょ姷鍋為敃銏ゃ€佸▎鎾村殐闁冲搫顑囬獮銏ゆ⒒閸屾瑦绁版い顐㈩槸閻e嘲螣閼测晝鐓嬪銈嗘閿熴儲绂嶈ぐ鎺撶厵闁绘垶蓱鐏忣厼霉濠婂啰绉烘慨濠呮缁辨帒螣閾忛€涙闂備焦瀵уú宥夊疾濞戞粎浜遍梻浣告啞濞诧箓宕归柆宥呯厱闁硅揪闄勯悡娆撴煠濞村娅呭ù鐘崇矊閳规垿鍨鹃悙钘変划闂佽鍠楅〃鍛村煡婢舵劕绠抽柟鎯ь嚟瑜板洨绱撻崒娆戣窗闁哥姵鐗犻、鏍川閹碱厽鏅i梺绋跨箳閸樠呮閻愮繝绻嗘い鏍ㄧ矌鐢稒绻涢崨顓熷枠婵﹦绮幏鍛存偡闁箑娈濈紓鍌欐祰椤曆囧磹閸噮鍤曠紓浣贯缚缁♀偓闂佹悶鍎崝宥呪枍閸ヮ剚鈷戠紒瀣濠€鎵磼鐎n偅宕岀€规洏鍨介幃浠嬪川婵犲嫬骞楅梺鐟板悑閻n亪宕规繝姘厐闁哄洢鍨洪悡銉︽叏濡灝鐓愰柣鎾跺枛閻擃偊宕堕妷銉ュБ缂備礁顑堝畷鐢垫閹烘梻纾兼俊顖濆亹閻h櫣绱撴担铏瑰笡缂佽鐗嗛悾宄邦潨閳ь剚淇婂宀婃Ш缂備浇椴哥换鍫濐潖缂佹ɑ濯寸紒娑橆儏濞堟劙姊洪幖鐐插闁告鍟块悾鐑筋敍閻愯尙楠囬梺鐟邦嚟婵潧鈻撴ィ鍐┾拺缂備焦蓱閳锋帡鏌嶅畡鎵ⅵ鐎殿噮鍋婂畷鎺楁倷鐎电ǹ骞堥梻浣瑰▕閺侇噣宕戦幘缁樼厸闁告侗鍠氶幊鍛繆閸欏濮囬摶锝夋偠濞戞帒澧查柡鍌楀亾闂傚倷鑳剁划顖炲礉閺囩倣鐔哥節閸パ冩優闂佺粯鏌ㄩ惃婵嬪绩閼恒儯浜滈柡鍐ㄦ处椤ュ鏌涢弬璇测偓婵嬪箺閸洘鍊烽柣鎴炨缚閸橀亶姊洪崫鍕偍闁告柨鏈弲鍫曨敍閻愬鍘卞┑鐐叉缁绘帞绮绘繝姘厸閻忕偟鏅晥閻庤娲﹂崑濠傜暦閻旂⒈鏁嗛柍褜鍓欓埢宥夋晲閸モ晝锛濇繛杈剧稻瑜板啯绂嶉悙顒傜瘈闁靛骏绲剧涵鐐亜閹存繃宸濈紒顔剧帛閵堬綁宕橀埡鍐ㄥ箥闂佽瀛╃粙鎺戠幓鐠恒劎涓嶆慨妞诲亾闁哄被鍔岄埥澶娢熸径鐧哥稻閵囧嫰濡搁敐鍛Е闂佽鍠楅悷鈺呫€侀弮鍫濈妞ゆ挻绻勭粈鍕⒒閸屾瑦绁版い鏇熺墵瀹曚即寮介銈囶槸婵犵數濮撮崐濠氬汲閿曞倹鐓欐い鏍仜娴滅増淇婇懠棰濆殭闁宠鍨块崺鍕礃閵娧呫偡婵$偑鍊ら崢楣冨礂濡警鍤曢悹鍥ㄧゴ濡插牓鏌曡箛鏇烆潔闁冲搫鎳忛悡蹇擃熆鐠鸿櫣澧曢柛鏃€鎸抽弻娑㈠棘濞嗙偓楔缂備浇椴搁幐濠氬箯閸涱垳鐭欓幖瀛樻尭娴滈箖鏌涘┑鍕姢闁活厽鎸鹃幉鎼佹偋閸繄鐟ㄩ梺鍝勵儎缁舵岸寮婚悢鐓庣鐟滃繒鏁☉銏$厸闁告侗鍠楅崐鎰版煛鐏炶濮傞柟顔哄€濆畷鎺戔槈濮楀棔绱� ---闂傚倸鍊搁崐鎼佸磹閹间礁纾归柣鎴eГ閸婂潡鏌ㄩ弮鍫熸殰闁稿鎸剧划顓炩槈濡搫绠诲┑鐐叉▕娴滄粓鎮″☉銏$厱婵炴垵宕獮妯汇亜閺傛寧顥㈡慨濠呮閹瑰嫰濡搁妷锔惧綒闂備胶鎳撻崵鏍箯閿燂拷
开发学院WEB开发Jsp 最大化JAVA代码的可重用性 阅读

最大化JAVA代码的可重用性

 2008-01-05 19:37:10 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣捣閻棗銆掑锝呬壕濡ょ姷鍋涢ˇ鐢稿极閹剧粯鍋愰柟缁樺笧閳ь剦鍙冨鍝勑ч崶褏浠奸梺璇茬箲閼归箖鎮鹃悜钘夎摕闁靛濡囬崢鐢告⒑鐟欏嫷鍟忛柛鐘崇墵閵嗗倹绺介崨濠勫幈闁硅壈鎻槐鏇熺墡闂備線娼уú銈団偓姘嵆閻涱噣骞掑Δ鈧粻锝嗙節闂堟稑鏆欏ù婊堢畺閺岋綁濮€閳惰泛婀辨竟鏇熺節濮橆厾鍘甸梺缁樺姦閸撴岸鎮樻潏銊ょ箚闁圭粯甯炴晶娑氱磼缂佹ḿ娲寸€规洖宕灃闁告劕鍟犻崜婵堟崲濞戞ḿ鏆嗗┑鐘辫兌閺佹牜绱撴担浠嬪摵闁圭懓娲ら悾鐑藉箳閹搭厽鍍甸梺鐟板悁閻掞箓鎮楅幖浣光拻濞达絿鍎ら崵鈧梺鎼炲€栭悧鐘荤嵁韫囨稒鏅搁柨鐕傛嫹婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繑銇勯幘鍗炵仼缂佺媭鍨堕弻娑㈠箛闂堟稒鐏堥悗鐟版啞缁诲啴濡甸崟顖氱閻庨潧鎽滈悾濂告⒑绾拋娼愭繛鑼枎椤繒绱掑Ο鑲╂嚌闂侀€炲苯澧畝锝堝劵椤︽煡鎮¢妶澶嬬厪闁割偅绻冮崑顏呯箾瀹割喕绨婚幆鐔兼⒑鐎圭姵銆冮柤鍐茬埣瀹曟繈鏁冮埀顒勨€旈崘顔嘉ч柛鈩冾殘閻熸劙姊洪悡搴℃毐闁绘牕銈稿畷鐑樼節閸パ冨祮闂侀潧楠忕槐鏇㈠储椤忓牊鈷戦柟鑲╁仜閸旀鏌¢崨顔锯姇缂佸倹甯熼ˇ瀵哥磼鏉堛劌绗氭繛鐓庣箻閸┾剝鎷呴柨瀣垫綗闂傚倷娴囧銊╂倿閿曞倸绠查柛銉墮閺嬩線鏌熼崜褏甯涢柡鍛倐閺屻劑鎮ら崒娑橆伓闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�  闂傚倸鍊搁崐鎼佸磹閹间礁纾归柣鎴eГ閸ゅ嫰鏌ら崫銉︽毄濞寸姵姘ㄧ槐鎾诲磼濞嗘帒鍘$紓渚囧櫘閸ㄥ爼濡撮崘顔煎窛闁哄鍨归崢娲倵楠炲灝鍔氭い锔诲灦瀹曪繝骞庨懞銉у帾闂婎偄娲﹀ú鏍ㄧ墡闂備浇顕х€垫帡宕滈悢濂夋綎闁惧繐婀辩壕鍏间繆椤栨碍鎯堟い顐㈢焸濮婅櫣鎷犻懠顒傤唹濠殿喗菧閸旀垿宕洪埀顒併亜閹哄秶顦﹂柛銈庡墴閺屾盯骞樼捄鐑樼€诲銈庡亜缁绘劗鍙呭銈呯箰鐎氼剟鎮楅鐑嗘富闁靛牆妫欑粈鈧梺鐟板暱闁帮絽鐣峰⿰鍕嚤閻庢稒菤閹锋椽姊绘笟鍥т簽闁稿鐩幊鐔碱敍濞戞瑦鐝峰銈嗘煥婢х晫澹曢悡搴唵閻犺櫣灏ㄩ崝鐔虹磼婢跺孩顏犻柍褜鍓氶鏍窗閺嶎厸鈧箓鏌ㄧ€b晝绠氬┑顔界箓閻牆危閻戣姤鈷戠紒瀣儥閸庢劙鏌熼悷鐗堟悙閾荤偤鏌涢幇鈺佸Ψ婵℃彃鐗婄换娑㈠幢濡ゅ啰顔夊┑鐐茬墛閿曘垹顫忕紒妯诲濡炲绨肩憰鍡欑磽閸屾氨袦闁稿鎸荤换娑氣偓娑欋缚閻倝鏌涢幘璺烘灈鐎规洘妞介崺鈧い鎺嶉檷娴滄粓鏌熼悜妯虹仴闁逞屽墮缂嶅﹤顕i幎绛嬫晢闁告洦鍓涢崢閬嶆煟鎼搭垳绉靛ù婊呭厴閻擃剟顢楅崒妤€浜鹃悷娆忓绾惧鏌涘Δ鈧崯鍧楊敋閿濆纾归柣鏇氱劍闉嬮梻鍌欑閹碱偄螞鐎靛摜涓嶉柟鎹愵嚙閽冪喖鏌曟繛鐐珕闁稿妫濋弻娑氫沪閸撗€妲堝銈呴獜閹凤拷
核心提示: ——克服传统OO方法在重用方面的缺陷摘要:不要放弃编写可重用代码的努力!本文介绍了三种对现有代码进行修改以提高其可重用性的方法,在程序员中似乎存在着一种日益普遍的观点,最大化JAVA代码的可重用性,认为重用只是一个神话,或许是传统的面向对象编程方法中所存在的不足增加了


——克服传统OO方法在重用方面的缺陷

摘要:不要放弃编写可重用代码的努力!本文介绍了三种对现有代码进行修改以提高其可重用性的方法。

在程序员中似乎存在着一种日益普遍的观点,认为重用只是一个神话。或许是传统的面向对象编程方法中所存在的不足增加了重用的困难。本文介绍了从另外一种不同的途径使重用成为可能的三个步骤。

第一步:将功能实现从类实例的方法中移出

由于缺乏精确性,类继续不是非常理想的代码重用机制。换句话说,假如不继续一个类的数据成员和其他的方法,那么你就无法重用这个类的某个单独的方法。这些额外的不必要的负担使方法重用的代码变得复杂。派生类对其父类的依靠性也以入了额外的复杂性:对父类的改动会对子类造成影响;当修改任意一个类的时候,我们很难记得清哪个方法被覆盖,哪个没有;而且被覆盖的方法是否会调用父类中相应的方法并不非常清楚地显现。

任何执行单一概念任务的方法应该能够成为代码用的首选而独立存在。为了达到这个目标,我们必须会到过程化的编程模式,将代码从类实例的方法中移出,形成具有全局可见性的过程。为了提高这种过程的可重用性,过程代码应该象静态的通用方法一样编写:每个过程只能使用自己的输入参数,只能调用其他全局性的过程完成其工作,不能使用任何非本地的变量。这种对外部依靠的简化降低了过程使用的复杂性,也增加了在其他地方使用此过程的可能性。当然,由于其结构通常会变得更为清楚,即使抛开重用的目的不谈我们也可以从这种代码的组织方式中受益。

在java中,方法不能脱离类而单独存在。因此,你可以对相关的过程进行组织并使它们成为一个独立的类中的公共静态方法。例如,对于如下所示的一个类:

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() { return pPolygon.containsPoint(this, p);}



}

在此处,nPolygon应该是这个样子:

class pPolygon {

static public int computePerimeter(Polygon polygon) {...}

static public boolean isConvex(Polygon polygon) {...}

static public boolean containsPoint(Polygon polygon, Point p) {...}



从类的名字pPolygon可以看出,该类所封装的过程主要与Polygon类型的对象有关。名字前面的p表示该类的唯一目的是组织公共静态过程。在Java中,类的名字以小写字母开头不是一种标准的做法,但象pPloygon这样的类事实上并不执行普通类的功能。也就是说,它并不代表着一类对象,它只是语言本身所需要的用于代码组织的实体。

 在上面这个例子中,改动代码的总体影响是使得客户代码不必为了重用其功能而从Polygon继续。Polygon类的功能现在已经由pPolygon类以过程为单位提供。客户代码只使用自己需要的代码,无需关心自身并不需要的功能。

这并不意味着在这种新型的过程化编程模式中,类不服务于更有用的目的。恰恰相反,类执行组织和封装对象数据成员的必要工作。而且它们通过多重接口实现多态性的能力也为代码重用提供了显著的支持,这将在下一个步骤中讨论。然而,由于将功能实现包含在实例方法中无法实现理想的代码重用,所以通过类继续实现代码重用和多态性支持也不应成为最佳的技术选择。

在一本被广为阅读的书《Design Patterns》中曾简要地提及一种略有不同的技术。策略模式(Strategy Pattern)提倡将相关算法的每个成员封装在一个通用的接口下,以便于客户端代码可交换地使用其算法。由于一个算法通常被作为一个或几个独立的过程进行编码,这种封装更注重执行单独任务的过程的重用,而不是执行多种任务的、包含代码和数据的对象的重用。这一步骤体现了相同的基本思想。

然而,将一个算法封装在一个接口下意味着将算法作为实现接口的对象进行编码。这意味着我们仍然依靠于一个与所包装的对象的数据和其他方法相耦合的过程,这样便会使其复用变得复杂。此外还存在这样一个问题,每次需要使用这个算法的时候都必须实例化这些对象,这便会降低程序的性能。值得庆幸的是,设计模式提供了针对这两个问题的解决方法。可以在对策略对象进行编码时应用享元模式(Flyweight Pattern,译者注:还存在一种译法为轻量模式),这样每个对象只会存在一个被共知共享的实例(这针对程序性能的问题),而且每个共享对象在访问间隔中并不维持状态(于是对象将没有数据成员,这针对大多数的耦合问题)。由此产生的享元--策略模式非常类似于在这一步骤中所提到的将功能实现封装在全局可见的、无状态的过程中的技术。(译者注:以上这两段文字读起来可能有些晦涩难解,建议有爱好的读者参阅文中所提到《设计模式》一书,Erich Gamma等著、李英军等译、机械工业出版社出版。)

第二步:将非原始的输入参数类型改为接口类型

在面向对象编程中,代码重用的真正基础在于通过接口参数类型利用多态性,而不是通过类继续,正如Allen Holub在 “Build User Interfaces for Object-Oriented System, Part 2”中所述:

“……你应该通过对接口而不是类编程实现重用。假如一个方法的所有参数都是某个已知接口的引用,这个接口由一些你所不知道的类实现,那么这个方法就能够操作这样一些对象:当编写方法的代码时,这些对象的类甚至还不存在。从技术上讲,可重用的是方法,而不是传递给方法的对象。”

将Holub所讲的方法应用于第一步所得到的结果,只要某块功能代码能够作为一个全局可见的过程而独立存在,你就可以将其每个类类型(class-type)的输入参数改为一个接口类型,这样便能进一步提高其重用的潜力。那么,实现此接口类型的任何类的对象都可以作为参数使用,而不仅仅局限于原始类。由此,这个过程对可能存在的大量的对象类型都成为可用的。

例如,有这样一个全局可见的静态过程

static public boolean contains(Rectangle rect, int x, int y) {…}

这个方法用于检查给定的矩形是否包含某个给定的点。在这个例子中,rect参数的类型可以从Rectangle类改变为接口类型,如下所示:

static public boolean contains(Rectangular rect, int x, int y){…}

Rectangular可以是下面形式的接口:

public interface Rectangular{

    Rectangle getBounds();

}

现在,所有可以被描述为矩形的类(也就意味着实现了Rectangular接口)的对象都可以作为传递给PRectangular.contains()的rect参数。通过放宽所传递的参数类型的限制,我们使方法具有更好的可重用性。

不过,在上面这个例子中,Rectangular接口的getBounds方法返回一个Rectangle类型,你可能会怀疑使用这个接口是否具有真正的价值;换句话说,假如我们知道传入过程的对象会在被调用时返回一个Rectangle,为什么不直接传入Rectangle取代接口类型呢?不这样做的最重要原因与集合有关,假设有这样一个方法:

static public boolean areAnyOverlapping(Collection rects) {…}

这个方法的目的在于检查给定集合中的任意矩形对象是否存在重叠。那么,在方法内部遍历集合中的每个对象时,假如无法将对象造型(cast)成如Rectangular这样的接口类型,那么将如何能够访问对象的矩形区域呢?唯一的选择是将对象造型成为其特定的类型(我们直到它有一个能够返回rectangle的方法),这意味着方法必须事先知道其所要操作的是什么类型。这恰恰是这一步骤力图首先要避免的问题!

第三步:选择低耦合的输入参数接口类型

完成第二步之后,应该选择什么样的接口类型来取代给定的类型呢?答案是能够通过参数完全描述过程的需求,同时又具有最少的额外负担的接口类型。参数对象所要实现的接口越简单,其他特定类实现此接口的机会就越大——由此,其对象可以作为参数使用的类也就越多。通过下面的例子可以很轻易地看到这点:

static public boolean areOverlapping(Window window1, Window window2) {...}

这个方法用于检查两个窗口(假定是矩形窗口)是否重叠,假如这个方法只要求从参数获得两个窗口的矩形坐标,那么简化参数的类型使其能反映这个事实是一种更好的选择:

static public boolean areOverlapping(Rectangular rect1, Rectangular rect2) {...}

以上的代码假设先前的Window类型的对象同样可以实现Rectangular接口。现在对于所有的矩形对象,都可以重用第一个方法所包含的功能了。

你可能多次体验到当一个接口能够完全确定需要通过参数获哪那些内容时,会存在太多不必要的方法。在这种情况下,应该在全局命名空间中定义一个新的公共接口以供其他可能面临同一困境的方法重用。

你可能还会不止一次地发现,在确定需要通过单一过程的一个参数获取哪些内容时,最好创建一个单独的接口。你应该只为这个参数使用此接口。这通常会在你希望如同C语言中的函数指针一样使用参数的情况下出现。例如下面的过程:

static public void sort(List list, SortComparison comp) {...}

此过程使用参数所提供的比较对象comp,通过比较给定列表中的所有对象而对其进行排序,sort对comp的全部要求是调用一个单独的方法进行比较。因此,SortComparison应该是只带有一个方法的接口:

public interface SortComparison {

boolean comesBefore(Object a, Object b);

}

这个接口的唯一目的是为sort提供一个与其完成任务所需功能相联系的钩子(hook),因此SortComparison无法在其他地方重用。

结束语

以上所述的三个步骤用于现有的、按照相对传统的面向对象方法所编写的代码。这些步骤与面向对象编程技术结合就形成了一种可以运用于今后代码编写中的新方法,它可以提高代码的可重用性和内聚性,同时降低了耦合度及复杂性。

很显然,这些步骤无法运用于那些在本质上就不适合于重用的代码。这类代码通常出现在应用程序的表示层(presentation layer)。例如程序中用于创建用户界面的代码,以及将输入事件与完成实际工作的过程相联系的控制代码,都是属于那种其功能在不同的程序中差别很大的代码,这种代码的重用几乎是不可能的。


Tags:最大化 JAVA 代码

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接