2008-11-06 55 views
8

我正在實現一個類來比較目錄樹(在C#中)。起初,我在類的構造函數中實現了實際的比較。像這樣:在構造函數中做冗長的操作被認爲是不好的設計嗎?

DirectoryComparer c = new DirectoryComparer("C:\\Dir1", "C:\\Dir2"); 

但是在構造函數中做一個可能的冗長操作並不覺得「正確」。另一種方法是使構造函數保密並添加如下靜態方法:

DirectoryComparer c = DirectoryComparer.Compare("C:\\Dir1", "C:\\Dir2"); 

您認爲如何?你期望構造函數是「快速」嗎?第二個例子是否更好,還是使這個類的用法複雜化?

BTW:

我不會標註任何答案,因爲接受了,因爲我不認爲這是一個正確的答案,只是喜好和品味。

編輯:

只是爲了澄清我的例子一點點。我不僅感興趣,如果目錄不同,我也有興趣他們如何不同(哪些文件)。所以一個簡單的int返回值就不夠了。 cdragon76.myopenid.com的答案實際上非常接近我想要的(+1給你)。

+1

如果你不會標記答案,也許這應該是一個社區維基? – 2009-03-13 07:48:04

+0

我同意[10chars] – 2009-03-13 07:51:28

回答

10

我更喜歡第二個。

我期望構造函數實例化類。 方法比較完成它設計的目的。

3

你不應該做任何可能在構造函數中失敗的東西。你不想永遠創建無效的對象。雖然你可以實現一個「殭屍」狀態,但是對象沒有太多的工作,在獨立的方法中執行任何複雜的邏輯要好得多。

+0

構造函數失敗並拋出異常是完全可以的。框架中有很多這方面的例子。它應該確保它在構造函數中不會泄漏對自身的引用,但除此之外它沒有問題。並不是說我喜歡複雜的構造函數,請介意一下。 – 2008-11-06 20:06:15

2

是的,通常構造函數是快速的,它被設計爲準備使用的對象,而不是實際的操作。我喜歡你的第二個選擇,因爲它保持了一線操作。

通過允許構造函數傳遞兩個路徑,然後有一個實際執行處理的Compare()方法,您也可以使它更容易一些。

5

我認爲一個接口可能就是你所追求的。我會創建一個類來表示一個目錄,並實現DirectoryComparer接口。該界面將包含比較方法。如果C#已經有一個Comparable接口,那麼你也可以實現它。

在代碼中,您的通話將是:

D1 = new Directory("C:\"); 
.. 
D1.compare(D2); 
1

我喜歡第二個例子,因爲它解釋究竟是什麼發生的事情,當你實例化對象。另外,我總是使用構造函數初始化所有的全局設置。

12

我認爲兩者的組合是「正確的」選擇,因爲我期望Compare方法返回比較結果,而不是比較器本身。

DirectoryComparer c = new DirectoryComparer(); 

int equality = c.Compare("C:\\Dir1", "C:\\Dir2"); 

...和達納提到,有在.NET中IComparer接口反映了這種模式。

IComparer.Compare方法因爲使用的IComparer類是主要與排序返回int。一般模式雖然適合的問題,所述問題:

  1. 構造與(可選地)「配置」參數
  2. 比較方法有兩個「數據」的參數,對它們進行比較,並返回一個「結果初始化一個實例「

現在,結果可以是int,bool,diffs集合。無論符合需求。

1

我想了通用比較器可能在建設只想指定要比較的文件,然後比較later-這種方式還可以實現擴展的邏輯:

  • 比較再次 - 是什麼,如果目錄改變了?
  • 通過更新成員來更改您正在比較的文件。

另外,您可能希望在實現中考慮在目標目錄中更改文件時從操作系統接收消息,並可以再次重新編譯。

是 - 你是假設這一類將僅被一次對這些文件的單個實例比較施加限制的點。

因此,我更喜歡:

DirectoryComparer = new DirectoryComparer(&Dir1,&Dir2);

DirectoryComparer->Compare();

或者

DirectoryComparer = new DirectoryComparer();

DirectoryComparer->Compare(&Dir1,&Dir2);

0

如果您正在使用C#的工作,你可以使用擴展方法來比較2根目錄創建一個方法,你將附加到DirectoryClass中的構建,因此它會看起來像這樣:

Directory dir1 = new Directory("C:\....."); 
Directory dir2 = new Directory("D:\....."); 

DirectoryCompare c = dir1.CompareTo(dir2); 

這將是更清晰的實施。 更多關於延伸方法here

0

如果操作可能需要很長時間的未知量,它是一個操作您可能要導出到不同的線程(所以你的主線程不會阻止,並可以做其他事情,如顯示爲一個旋轉進度指示器例)。其他應用程序可能不希望這樣做,他們可能希望在單個線程中執行所有操作(例如那些沒有UI的應用程序)。移動對象創建到一個單獨的線程是有點尷尬恕我直言。我寧願在當前線程中快速創建對象,然後讓它的一個方法在另一個線程中運行,一旦方法完成運行,另一個線程就會死掉,我可以在我的方法中獲取此方法的結果當我知道結果時(或者如果結果涉及更多細節,我可能必須一次使用一個結果),我很快樂,因爲在轉儲對象之前使用對象的另一種方法處理當前線程。

3

我同意不在構造函數中做冗長操作的一般情緒。

此外,雖然在設計的主題,我會考慮改變你的第二個例子,以便DirectoryComparer.Compare方法返回的東西而不是DirectoryComparer對象。 (可能是一個新類,稱爲DirectoryDifferencesDirectoryComparisonResult。)DirectoryComparer類型的對象聽起來像是用來比較目錄的對象,而不是表示一對目錄之間差異的對象。

然後,如果您想要定義不同的比較目錄的方法(例如忽略時間戳,只讀屬性,空目錄等),則可以將這些參數傳遞給DirectoryComparer類構造函數。或者,如果您始終希望DirectoryComparer具有完全相同的比較目錄規則,則可以簡單地將DirectoryComparer設置爲靜態類。

例如:

DirectoryComparer comparer = new DirectoryComparer(
    DirectoryComparerOptions.IgnoreDirectoryAttributes 
); 
DirectoryComparerResult result = comparer.Compare("C:\\Dir1", "C:\\Dir2"); 
0

如果參數只是要處理一次,然後我不認爲他們屬於既作爲構造函數參數或實例的狀態。

但是,如果比較服務將支持某種可掛起算法,或者當兩個目錄的相等狀態根據文件系統事件或類似事件發生更改時要通知偵聽器。那麼它的目錄就是實例狀態的一部分。

在任何情況下,構造函數都不會執行除初始化實例之外的任何其他工作。在算法上面的兩個情況是由客戶端驅動的,就像一個迭代器,或者它是由事件監聽線程驅動的。

我一般會試着做這樣的事情: 如果它可以作爲參數傳遞給服務方法,那麼不要在實例中保存狀態。 嘗試設計具有不可變狀態的對象。 定義屬性,比如在equals和hashcode中使用的屬性應該是不可變的。

Conceptualy構造函數是一個將對象表示映射到它所表示的對象的函數。由於Integer.valueOf(1)== Integer.valueOf(1),Integer.valueOf(1)實際上比新的Integer(1)更多的構造函數。 , 在這兩種情況下,這個概念也意味着所有的cosntructor參數,只有構造函數參數應該定義一個對象的等號行爲。

0

我肯定會做第二個。

如果構造函數中的長操作實際上是在構建該對象以使其可用,那麼它們很好。

現在我看到人們在構造函數中做的一件事是調用虛擬方法。這是不好的,因爲一旦有人使用你作爲基類並覆蓋了其中一個函數,一旦你進入你的構造函數,你將調用基類的版本而不是派生類。

0

我不認爲像「冗長」這樣的抽象術語談論與決定有任何關係,如果你把某些東西放在構造函數中。

構造函數是應該用來初始化一個對象的東西,應該用一個方法來「做某事」,即有一個函數。

1

我認爲構造函數不僅可以根據需要花費盡可能多的時間來構造一個有效的對象,但構造函數需要這樣做。推遲創建對象非常糟糕,因爲最終會導致潛在的無效對象。所以,在你觸摸它之前,你必須每次檢查一個對象(這是在MFC中完成的方法,無處不在)。

我只看到創建對象的兩種方式略有不同。無論如何,我們可以將新運算符看作該類的靜態函數。所以,這一切都歸結爲語法糖。

DirectoryComparer類是做什麼的?這是什麼責任?從我的角度來看(這是一個C++程序員的觀點),看起來像使用免費函數會更好,但我認爲您不能在C#中使用自由函數,對嗎?我猜你會收集DirectoryComparer對象中不同的文件。如果是這樣,你可以更好地創建類似於文件數組或者相應命名的等效類。

相關問題