簡體   English   中英

返回派生類型的接口

[英]Interface returning derived types

class Result
{
   public string Data { get; set; }
}

interface IRepository
{
   Result[] Search(string data);
}

我有一個相當通用的接口,它搜索“某物”並返回Result IRepository接口可以由幾個類實現,每個類都返回帶有自己唯一的元數據的自己的Result。 例如,我可以擁有一個DiskRepository來搜索磁盤上的數據:

class DiskResult : Result
{
   public int FileSize { get; set; }
   public DateTime LastModifiedDate { get; set; }
}

class DiskRepository : IRepository
{
   public Result[] Search(string data) 
   {
      // ...
      DiskResult[] results = GetDataFromSomewhere();
      return results;
   } 
}

DiskResult包含有關特定於DiskRespository的結果的DiskRespository 如果我創建了另一個實現IRepository類,則該特定實現可能具有該類獨特的元數據集。

最后,我希望搜索控制器如下所示:

class SearchController 
{
   private IRepository[] _repositories;

   public SearchController(IRepository[] repositories)
   {
      _repositories = repositories;
   }

   public void Display(string data)
   {
      Result[] results = _repositories.Search(data);
      // Display results
   }
}

我可以輕松地在Result類上顯示Data屬性,但是是否有一種很好的模式來顯示從Result派生的每個類的元數據? 我可以有一堆if語句來檢查類是否為類型,但這感覺有些笨拙。 有沒有更好的方法來完成我要達到的目標?

其中一條評論正確指出,將虛擬Display()添加到Result類中是違反單一職責原則的。 完全正確。

這是您的問題的答案:因為您想做這樣的事情:

private IRepository[] _repositories;

...無法避免在運行時進行類型檢查。 編譯器不知道將返回哪個子類type-from-from-Result。 所有它知道您的存儲庫都返回一個Result派生對象。

另一方面,如果您使用泛型:

interface IRepository<T> where T : Result
{
    T[] Search(string data);
}

...您將在編譯時知道您要處理的Result的子類類型,從而避免了類型檢查的需要,以及從第一種方法開始的長串“ if”語句。

如果您可以堅持使用泛型,那么可以執行以下操作:

interface IResultDisplayService<T> where T : Result
{
    void Display(T result);
}

因此,我想我的問題是:是否必須存儲這些存儲庫的數組? 有哪些現實世界的使用場景?

我不會為此使用存儲庫接口,而是創建一個新接口:

public interface ISearchProvider
{
    IEnumerable<SearchResultItem> Search(string keyword);
}

public interface ISearchResultItem
{
    string Title {get; }
    string Description {get; }
    NameValueCollection Metadata {get; }
}

標題和描述應足以滿足90%的搜索用例。 例如, DiskResult可能在Description屬性中包含文件夾等。 元數據可以顯示在工具提示或詳細信息視圖中。

如果那還不夠,我也會創建一個渲染界面:

public interface ISearchResultRenderer
{
    bool IsValidFor(Type type);
    void Render(Stream stream);
}

並具有一個DiskResultHtmlRenderer實現,該實現將遍歷元數據並正確地對其進行結構化。

您可以將IRepository通用接口,例如:

interface IRepository<T>
{
    T[] Search(string data);
}

您可以在結果類中有一個virtual方法來顯示結果。 您的子類可以override它,並可以給出自己的實現。 這樣做時,當您調用Display方法時,您的Result對象將調用相應的方法進行顯示。

像這樣

class Result
{
     public virtual void Display()
     {
          //Your Code

     }
     //Your Code   
}

class DiskResult : Result
{
     public override void Display()
     {
          //Your Code
     }
     //Your Code
}

您的Display方式

public void Display(string data)
{
   Result[] results = _repositories.Search(data);

   // Display results
   foreach(var result in results)
   {
      result.Display();
   }

}

希望這對您有所幫助。

暫無
暫無

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

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