返回派生类型的接口
本文关键字:接口 类型 派生 返回 | 更新日期: 2023-09-27 18:25:49
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
的结果的额外信息。 如果我创建了另一个实现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
语句来检查类是否属于某种类型,但这感觉有点笨拙。 有没有更好的方法来实现我想要实现的目标?
我不会为此使用存储库接口,而是创建一个新接口:
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
实现,它通过元数据并正确构建它。
其中一条注释正确地指出,将虚拟 Display(( 添加到 Result 类是违反单一责任原则的。 完全正确。
这是与你的问题的摩擦:因为你想做这样的事情:
private IRepository[] _repositories;
。无法避免在运行时执行类型检查。 编译器不知道将返回哪个子类类型派生自 Result。 它所知道的只是您的存储库返回一个 Result 派生对象。
另一方面,如果使用泛型:
interface IRepository<T> where T : Result
{
T[] Search(string data);
}
。在编译时,您将知道您正在处理的结果的子类类型,从而消除了类型检查的需要,以及从第一种方法开始的一长串"if"语句。
如果你能坚持使用泛型,那么你可以做这样的事情:
interface IResultDisplayService<T> where T : Result
{
void Display(T result);
}
所以,我想我的问题是:是否必须存储这些存储库的数组? 有哪些真实的使用场景?
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();
}
}
希望这对你有帮助。