2010-07-16 106 views
4

我越是寫入單元測試越多,我發現自己寫越來越小的類。這些類現在很小,因此它們中的許多隻有一個公共方法,它們與接口相關聯。然後,測試直接針對該公共方法,並且相當小(有時該公共方法將調用該類內部的私有方法)。然後我使用IOC容器來管理這些輕量級類的實例化,因爲它們有很多。編寫通常只有一種公開方法公開的類是否是一種很好的做法?

這是典型的嘗試以更多的TDD方式做事嗎?我擔心現在我已經重構了一個傳統的3000線類,其中有一種方法,因爲現在實際上大約有100個不同的類文件,這些類在另一方面也很難維護。

我在做什麼太過分了?我試圖用這種方法來遵循單一職責原則,但我可能會陷入一種貧乏的階級結構,我沒有非常聰明的「業務對象」。

回答

2

這個衆多的小班會讓我瘋狂。有了這種設計風格,真正很難弄清真正的工作在哪裏完成。我不是擁有大量每個具​​有相應實現類的接口的粉絲。有很多「IWidget」和「WidgetImpl」配對是我書中的代碼味道。

將3000條線條分成小塊是非常值得讚揚的。不過要記住的目標是:使代碼更易於閱讀和更容易使用。如果你最終得到30個職業和接口,你可能只是創造了一種不同類型的怪物。現在你有一個非常複雜的類設計。需要花費很多精力才能讓這些課程順利進行。而且有很多小班,你失去了打開幾個關鍵文件的非常有用的能力,選擇最重要的方法,並瞭解到底發生了什麼。

儘管我不太喜歡測試驅動設計,儘早編寫測試,這很明智。但重新組織和重構你的課堂設計,以便更容易地進行單元測試?不用了,謝謝。我只會在構建接口的時候才使用接口,而不是因爲我需要模擬一些對象,以便測試我的類。這是把馬車放在馬前。

1

如果你問這個問題,你可能會走得太遠。在類中只有一個公共方法並不壞,因爲如果該類具有明確的責任/功能並封裝了與該函數有關的所有邏輯,即使其中大部分都是私有方法。

當重構這樣的遺留代碼時,我通常會嘗試識別高層次的組件,這些組件可以分配不同的角色/職責並將它們分離到他們自己的類中。我認爲哪些功能應該是哪些組件的責任,並將這些方法轉移到該類中。

0

您編寫了一個類,以便該類的實例保持狀態。你把這個狀態放在一個類中,因爲類中的所有狀態都是相關的。你有函數來管理這個狀態,這樣就無法設置狀態的無效排列(臭名昭着的正方形有成員寬度和高度,但是如果寬度不不等於它不是一個真正的方形。)

如果你沒有狀態,你不需要一個類,你可以只使用免費函數(或在Java中,靜態函數)。

所以,問題不是「我應該有一個功能嗎?」而是「我的班級封裝的是什麼有狀態的實體?「

也許你有一個函數,將所有國家 - 和你應該讓更精細,使得例如,而不必void Rectangle::setWidthAndHeight(int x, int y)你應該有一個setWidth和獨立setHeight

也許你有。一個構造函數,設置東西,和一個單一的功能doesIt,不管「它」,然後你有函子,和一個doIt可能是有意義的。例如,class Add implements Operation { Add(int howmuch); Operand doIt(Operand rhs);}

(但你可能會發現,你真的想要像訪問者模式 - 一個純粹的f如果你有純粹的價值對象,那麼unctor更有可能;如果它們被安排在一棵樹中,並且彼此相關,訪客就更有可能)。

即使有這麼多小對象,單功能是正確的粒度級別,你可能想要像Facade Pattern這樣的東西來構造出原始操作,經常使用的複雜操作。

沒有人回答。如果你真的有一堆仿函數,那很酷。如果你真的只是把每個免費的功能變成一個班級,那是愚蠢的。

真正的答案在於回答這個問題:「我管理的是什麼狀態,以及我的班級如何模擬我的問題域?」

0

我會猜測,如果我沒有看到代碼給出了確定的答案。

但是,這聽起來像你擔心,這是審查代碼的明確標誌。你的問題的簡短回答可以回到definition of Simple Design。最少數量的類和方法就是其中之一。如果您覺得您可以拿走一些元素而不會失去其他所需的屬性,請繼續並摺疊/內聯它們。

一些指針,以幫助您決定:

  • 你有「單一職責」好好檢查一下?這是一個關鍵技能(我仍然沒有看到它像主人),看起來很困難。它不一定會轉化爲一種方法 - 類。一個好的標準是每班有5-7個公共方法。每個班級可以有0-5個合作者。同時爲了驗證SRP,問問什麼可以推動到這個類的變化?如果存在多個不相關的答案(例如,分組結構(解析)中的改變+將分組內容改變爲動作映射(命令調度器)),那麼可能需要對該類進行拆分。另一方面,如果你覺得數據包結構發生變化,會影響4個不同的類別 - 你已經跑掉了另一個懸崖;也許你需要把他們合併成一個有凝聚力的班級。
  • 如果您在命名具體實現時遇到困難,也許您不需要該接口。例如XXXImpl課程暗示XXX需要被關注。最近我瞭解到一個命名約定,其中接口描述了一個角色,並且實現是通過用於實現角色的技術來命名的(或者回退到它所做的)。例如XmppAuction實現拍賣(或狙擊手通知器實現AuctionEventListener)
  • 最後你是否發現很難添加/修改/測試現有代碼(例如測試設置很長或很痛苦)?這些可能是你需要重構的標誌。
相關問題