有人說(shuō)“TDD(測(cè)試驅(qū)動(dòng)開(kāi)發(fā))可以帶來(lái)優(yōu)秀的設(shè)計(jì)”,也有人說(shuō)“TDD會(huì)對(duì)設(shè)計(jì)有負(fù)面影響”。如果有個(gè)具體例子的話,討論起來(lái)會(huì)實(shí)際得多,所以下面我們來(lái)看一下私有方法以及它與優(yōu)秀設(shè)計(jì)、可測(cè)試性的關(guān)系——這種對(duì)立觀點(diǎn)的一個(gè)實(shí)例。 Szczepan Faber在博客中寫道,私有方法是一種反模式: 自從TDD誕生之日起,私有方法似乎就有了壞味道。被測(cè)試浸染的開(kāi)發(fā)者總想尋找測(cè)試私有方法的辦法。嗯……這顯然是很困難的,所以問(wèn)題就從“如何”變成了“為何”:為何要測(cè)試私有方法?大多數(shù)TDDers都會(huì)立刻回答說(shuō):別這么干。于是TDD又改變了我們構(gòu)建軟件的方式,對(duì)私有方法進(jìn)行了重新評(píng)估 Jay Fields在博客上描述了在ruby中測(cè)試私有方法的一種通用方式: ……我很少測(cè)試私有方法。我更傾向于通過(guò)public API來(lái)進(jìn)行測(cè)試。不過(guò)偶爾也有這種時(shí)候,如果你可以給一兩個(gè)私有方法寫點(diǎn)測(cè)試用例的話,日子就可以過(guò)的容易一些。 Michael Feathers在去年的The Deep Synergy Between Testability and Good Design一文中指出,TDD可以帶來(lái)優(yōu)秀的設(shè)計(jì),而反過(guò)來(lái)想,那些不可測(cè)試的代碼應(yīng)該引起我們的深思: 在我編寫測(cè)試時(shí),如果覺(jué)得有強(qiáng)烈的沖動(dòng)促使我去測(cè)試一個(gè)私有方法,我就會(huì)把它看作一種暗示。它告訴我,我的類已經(jīng)被封裝得趨近于封閉了,測(cè)試代碼無(wú)法再通過(guò)公共接口來(lái)“理解”這個(gè)類的行為。我順從了這個(gè)暗示的召喚,重新構(gòu)建了代碼。通常我都會(huì)把這個(gè)私有方法(可能還有一些相關(guān)的方法)挪到一個(gè)新的類里面,在那里它不再是私有,可以讓測(cè)試代碼訪問(wèn)。
以上種種想法,都傾向于不鼓勵(lì)使用私有方法,在天平的可測(cè)試性一端加入更多砝碼。但它們并不是唯一的聲音。實(shí)際上在我們所能看到的有關(guān)面向?qū)ο箝_(kāi)發(fā)的觀點(diǎn)中,很多都是支持少用一些類,極盡所能使用封裝。在public API中只暴露最小的API集合,就會(huì)將耦合降低到最小。David West在Object Thinking一書(shū)中,引用了Lorenz和Kidd在Object Oriented Software Metrics書(shū)中的論述:
一個(gè)應(yīng)用程序應(yīng)該最多包括40個(gè)故事,100個(gè)類。 應(yīng)用程序所屬的整個(gè)業(yè)務(wù)領(lǐng)域不應(yīng)該需要超過(guò)1000個(gè)類來(lái)完成。 每一次迭代后都該扔掉25-30%的代碼。 每個(gè)類的職責(zé):平均是7個(gè)。 每個(gè)類的方法數(shù):平均是12個(gè)。 每個(gè)方法的代碼行數(shù):平均是15個(gè)。 需要進(jìn)行注釋的代碼行數(shù)百分比:60。 case語(yǔ)句的數(shù)量:平均為0。 如果私有方法確實(shí)是壞味道,需要把它們挪到自己所應(yīng)歸屬的類中,這不就是“為了讓測(cè)試變得簡(jiǎn)單,而增加類的數(shù)量”么?它勢(shì)必會(huì)造成類的數(shù)量急劇膨脹。
那么該拿私有方法怎么辦呢?測(cè)試它們太折磨人了。我們可否修改一下,把它們暴露給測(cè)試代碼?或者不去測(cè)試私有方法,讓設(shè)計(jì)與可測(cè)試性永不相干?或者,私有方法是一種壞味道,它表明一個(gè)類做了太多事情?
|