2009-10-16 67 views
8

我有一個對象稱爲參數,從方法降低到方法,並通過包邊界調用樹。它有大約五十個狀態變量。每種方法可能使用一個或兩個變量來控制其輸出。上帝的對象 - 減少耦合到'主'對象

我認爲這是一個糟糕的主意,因爲我無法輕易地看到一個方法需要什麼功能,甚至如果對於與我當前模塊完全無關的模塊Y的某些參數組合,可能會發生什麼情況。

什麼是減少耦合到這個神物體,或理想地消除它的一些好技術?

 public void ExporterExcelParFonds(ParametresExecution parametres) 
    { 
     ApplicationExcel appExcel = null; 
     LogTool.Instance.ExceptionSoulevee = false; 


     bool inclureReferences = parametres.inclureReferences; 
     bool inclureBornes = parametres.inclureBornes; 
     DateTime dateDebut = parametres.date; 
     DateTime dateFin = parametres.dateFin; 

     try 
     { 
      LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference); 

      bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds); 
      if (!fichiersPreparesAvecSucces) 
      { 
       parametres.afficherRapportApresGeneration = false; 
       LogTool.Instance.ExceptionSoulevee = true; 
      } 
      else 
      { 

呼叫者會做:

   PortefeuillesReference pr = new PortefeuillesReference(); 
      pr.ExporterExcelParFonds(parametres); 
+0

「參數」是一個配置對象嗎? – 2009-10-16 20:25:56

+0

是的。用於讓UI帶有業務層可能需要的任何參數。 – 2009-10-16 20:28:41

回答

9

首先,冒着說明明顯的風險:傳遞所使用的參數方法,而不是上帝的對象。

但是,這可能會導致某些方法需要大量參數,因爲它們會調用其他方法,這些方法會依次調用其他方法,等等。這可能是將所有東西放在神物中的靈感。我將給出一個參數太多的這種方法的簡單例子;你必須想象「太多」 == 3這裏:-)

public void PrintFilteredReport(
    Data data, FilterCriteria criteria, ReportFormat format) 
{ 
    var filteredData = Filter(data, criteria); 
    PrintReport(filteredData, format); 
} 

因此問題是,我們如何能夠減少參數的數量,而不訴諸神的對象?答案是擺脫程序編程並充分利用面向對象的設計。對象可以使用對方,而不需要知道用來初始化及其合作者的參數:

// dataFilter service object only needs to know the criteria 
var dataFilter = new DataFilter(criteria); 

// report printer service object only needs to know the format 
var reportPrinter = new ReportPrinter(format); 

// filteredReportPrinter service object is initialized with a 
// dataFilter and a reportPrinter service, but it doesn't need 
// to know which parameters those are using to do their job 
var filteredReportPrinter = new FilteredReportPrinter(dataFilter, reportPrinter); 

現在FilteredReportPrinter.Print方法可以只用一個參數來實現:

public void Print(data) 
{ 
    var filteredData = this.dataFilter.Filter(data); 
    this.reportPrinter.Print(filteredData); 
} 

順便說一句,這關注和依賴注入的分離不僅僅是消除參數的好處。如果您訪問的合作者通過接口的對象,然後,讓你的類

  • 非常靈活:您可以設置FilteredReportPrinter與任何濾波器/打印機實現你能想象的
  • 很可測試:你可以通過與罐頭模擬合作者並驗證它們在單元測試中的使用是否正確
+1

最佳答案,在我看來。 – 2009-10-17 06:26:08

0

查詢每個客戶對他們所需要的參數,並注入他們?

示例:需要「參數」的每個「對象」都是「客戶端」。每個「客戶端」暴露一個接口,通過該接口「配置代理」查詢客戶端的所需參數。配置代理然後「注入」參數(並且只有客戶端需要)。

+0

你可以展開這個,也許有一個例子嗎?我認爲我同意這一點,但我想確定。 – gn22 2009-10-16 20:31:20

+0

我不明白。 – 2009-10-16 23:32:59

+0

我已添加詳細信息。 – jldupont 2009-10-16 23:52:32

1

如果你所有的方法都使用相同的Parameters類,那麼也許它應該是一個類的成員變量,並在其中包含相關的方法,那麼你可以將Parameters傳遞給這個類的構造函數,將它賦值給一個成員變量所有的方法都可以使用它作爲參數傳遞它。

開始重構這個神類的一個好方法是將它分解成更小的塊。查找相關的屬性組,並將它們分解到他們自己的類中。

然後,您可以重新訪問依賴於Parameters的方法,並查看是否可以使用您創建的其中一個較小的類來替換它。

很難給出一個好的解決方案,沒有一些代碼示例和真實世界的情況。

0

這聽起來像你沒有在你的設計中應用面向對象(OO)的原則。既然你提到了「對象」這個詞,我認爲你在某種面向對象的範式內工作。我建議你將你的「調用樹」轉換成模擬你正在解決的問題的對象。一個「神物」絕對是要避免的。我想你可能會錯過一些基本的東西......如果你發佈了一些代碼示例,我可能會更詳細地回答。

+0

是的,這是一個遺留系統,它寫得很差,我同意。 – 2009-10-16 20:38:28

+1

請發表一個代碼示例...你如何處理這種情況取決於細節。 – SingleShot 2009-10-16 20:40:22

-2

(我假設這是在Java或.NET環境中)將類轉換爲單例。添加一個名爲「getInstance()」的靜態方法或類似的調用來獲取名稱值包(並停止「tramping」它 - 參見第10章「代碼完成」一書)。

現在很難的部分。據推測,這是在一個網絡應用程序或其他非批次/單線程環境。因此,當對象不是真正的單例時,要訪問正確的實例,必須隱藏靜態訪問器內的選擇邏輯。

在java中,您可以設置一個「線程本地」引用,並在每個請求或子任務啓動時對其進行初始化。然後,根據該線程本地對訪問器進行編碼。我不知道.NET中是否存在類似的東西,但是你總是可以用一個使用當前線程實例作爲關鍵字的Dictionary(Hash,Map)來僞造它。

這是一個開始......(總是會分解blob本身,但是我構建了一個框架,其中有一個非常類似的半全球價值存儲區)

+3

我試圖避免有一個單身人士。我實際上不喜歡單身人士,因爲我曾經見過它。在這裏使用它會退後一步。 – 2009-10-16 23:59:47

+0

-1你需要threadlocal來減少「singleton」的「全局性」這一事實表明你不應該首先使用全局變量。無論如何,OP可能會談論單線程winforms應用程序。 – 2009-10-17 02:35:49

0

對於支配行爲的參數,可以實例化一個展示配置行爲的對象。然後,客戶端類簡單地使用實例化的對象 - 客戶端和服務都不必知道參數的值是什麼。例如,一個告訴從哪裏讀取數據的參數,讓FlatFileReader,XMLFileReader和DatabaseReader都繼承相同的基類(或實現相同的接口)。基於參數的值來實例化其中的一個,然後reader類的客戶端只需向實例化的reader對象請求數據,而不知道數據是來自文件還是來自數據庫。

要開始您可以將您的大ParametresExecution類分成幾個類,每個包只包含包的參數。

另一個方向可能是在施工時傳遞ParametresExecution對象。在每次函數調用時都不必傳遞它。