簡體   English   中英

在 class 構造函數中最好初始化什么?

[英]What to is best to initialize in a class constructor?

我有一個關於構造函數的設計問題。 在觀看了 google 關於“The Clean Code Talks”的視頻后,他談到了初始化類的重要性以及構造函數中的更多內容,以及更好的測試選項。 例如,在我的代碼中,我有一個 wcf 服務托管在服務 svc 構造器中的iis上,我們初始化整個服務。

 BService()
    {
        if (!m_DAL.Initilaze())
        {
            throw new Exception("Due to problems in the initialization B2BService is down");
        }

        m_sBadTransactionDir = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "BadTransaction";

        _address1 = new EndpointAddress(System.Configuration.ConfigurationManager.AppSettings["1Address"]);
        _address2 = new EndpointAddress(System.Configuration.ConfigurationManager.AppSettings["2Address"]);
        _address3 = new EndpointAddress(System.Configuration.ConfigurationManager.AppSettings["3Address"]);
        _address4 = new EndpointAddress(System.Configuration.ConfigurationManager.AppSettings["4Address"]);

        LoadSitesFromAdaptors();

        double interval1= Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings["interval1"]);
        m_sentTransactionTimer.Interval = interval1;
        m_sentTransactionTimer.Elapsed += Foo1;
        m_sentTransactionTimer.Start();

        double interval2 = Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings["interval2"]);
        m_checkStatusTimer.Interval = interval2 ;
        m_checkStatusTimer.Elapsed += Foo2;
        m_checkStatusTimer.Start();

        double interval3= Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings["interval3"]);
        m_adaptorsTimer.Interval = interval3;
        m_adaptorsTimer.Elapsed += Foo3;
        m_adaptorsTimer.Start();

.... and some more initialization code here


        Logger.Instance.Write("***************  Service is Up  ****************", "INFO");
    }

你們知道初始化大類的更好方法嗎? 使測試更容易,並且通常您對此事的看法?

如果這是服務的“主要” class,您可能不想對其進行單元測試。 或者,如果它具有您想要單元測試的功能,您可能希望將該功能移動到單獨的類中,這些類作為構造函數 arguments 獲取所需的配置參數(以及僅這些參數)。 因此它們很容易進行單元測試。

或者,如果你真的想測試這個 class,你可以將System.Configuration.ConfigurationManager隱藏在一個可模擬的接口后面,這樣你就可以輕松地傳遞單元測試所需的任何參數。 但一般來說,您的應用程序中幾乎總是有一些高級類,它們只是初始化整個東西,從命令行/配置文件/注冊表/數據庫/任何東西加載配置參數,並將這些傳遞給其他類做真正的工作。 在一個設計良好的應用程序中,這樣的類有這個單一的職責,它通過集成/系統測試而不是單元測試來驗證。

在較小的范圍內,上面的代碼在這些段中包含重復:

    double interval1= Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings["interval1"]);
    m_sentTransactionTimer.Interval = interval1;
    m_sentTransactionTimer.Elapsed += Foo1;
    m_sentTransactionTimer.Start();

這些可以很容易地提取到帶有參數的單個方法中。

只是粗略地看一下您的代碼,在我看來,它應該被重新考慮,這樣您就可以避免所有重復的代碼。

我發現減少重復的最佳方法是將重復的代碼抽象為帶有參數的小函數,或者使用字典和列表理解來創建初始設置,然后解析運行方法的列表。

這將創建非常整潔、易於閱讀和可維護的代碼。

可以重構為類似

var addressList = new List<string>() { "1Address", "2Address", "3Address" };
var composedAddress = new List<Address>();    
addressList.ForEach(address => composedAddress.Add(new EndpointAddress(
    System.Configuration.ConfigurationManager.AppSettings[address]))
);

此外,您可以對間隔做同樣的事情;

var intervalList = new List<Tuple<string, timer, delegate>>() { 
  new Tuple<string, timer, delegate> { "Interval1", m_sentTransactionTimer, Foo1 },  
  new Tuple<string, timer, delegate>  { "Interval2" m_checkStatusTimer, Foo2 }, 
  new Tuple<string, timer, delegate> { "Interval3", m_adaptorsTimer , Foo3 }  
}

intervalList.ForEach(tuple => {
  var interval = Convert.ToDouble(System.Configuration.ConfigurationManager.AppSettings[tuple.Item1])
  tuple.Item2.Interval = interval;
  tuple.Item2.Elapsed += tuple.Item3;
  tuple.Item2.Start();
});    

此外,您可能希望確保您的 BServiceClass 沒有承擔過多的責任。 class 應該只有 1 個責任。 遵循單一職責原則,您應該考慮抽象出任何似乎違反單一職責的代碼。

BService 構造函數應該是描述正在發生的事情的高階函數。

BService() {
    Initialize(addressList, intervalList, someotherList);
    Logger.Instance.Write("***************  Service is Up  ****************", "INFO");

}

Initialize(List<string>, List<Tuple<string, timer, delegate>>, ...){
  ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM