class Result
{
public string Data { get; set; }
}
interface IRepository
{
Result[] Search(string data);
}
I have a fairly generic interface that searches for "something" and returns a Result
. The IRepository
interface can be implemented by several classes, each returning their own Result with their own unique metadata. For example, I can have a DiskRepository
that searches for data on disk:
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;
}
}
The DiskResult
contains extra information about the result that is specific to the DiskRespository
. If I created another class that implements IRepository
, that specific implementation may have its own set of metadata unique to that class.
In the end, I'd like my search controller to look like this:
class SearchController
{
private IRepository[] _repositories;
public SearchController(IRepository[] repositories)
{
_repositories = repositories;
}
public void Display(string data)
{
Result[] results = _repositories.Search(data);
// Display results
}
}
I can easily display the Data
property on my Result
class, but is there a good pattern to display the metadata for each class that derives from Result
? I could have a bunch of if
statements to check if the class is of a type, but that feels a bit clunky. Is there a better way to do what I'm trying to achieve?
One of the comments correctly points out that adding a virtual Display() to your Result class is a violation of the Single Responsibility Principle. Completely true.
Here's the rub with your question: because you want to do things like this:
private IRepository[] _repositories;
... there's no way to avoid doing a type check at run time. The compiler has no idea what subclass type-derived-from-Result will be returned. All that it knows it that your Repository's return a Result derived object.
On the other hand, if you use generics:
interface IRepository<T> where T : Result
{
T[] Search(string data);
}
... you will, at compile time, know what subclass type of Result you're dealing with, thus obviating the need for type checking, and the long string of "if" statements that follow from the first approach.
If you can stick with using generics, then you can do stuff like this:
interface IResultDisplayService<T> where T : Result
{
void Display(T result);
}
So, I suppose my question is: is it imperative to store an array of these repositories? What real world usage scenario is there?
I would not use the repository interface for that, but create a new one:
public interface ISearchProvider
{
IEnumerable<SearchResultItem> Search(string keyword);
}
public interface ISearchResultItem
{
string Title {get; }
string Description {get; }
NameValueCollection Metadata {get; }
}
Title and description should be enough for 90% of the search cases. For instance, a DiskResult
might include folder etc in the Description
property. The metadata can be displayed in a tooltip or a details view.
If that's not enough I would create a render interface too:
public interface ISearchResultRenderer
{
bool IsValidFor(Type type);
void Render(Stream stream);
}
And have a DiskResultHtmlRenderer
implementation which goes through the metadata and structure it properly.
You could make IRepository
a generic interface like:
interface IRepository<T>
{
T[] Search(string data);
}
You can have a virtual
method in result class which will display the results. Your child class can override
it and can give their own implementation. Doing so when you call Display
method your Result
object will call respective method to do the display.
Something like this
class Result
{
public virtual void Display()
{
//Your Code
}
//Your Code
}
class DiskResult : Result
{
public override void Display()
{
//Your Code
}
//Your Code
}
Your Display
method
public void Display(string data)
{
Result[] results = _repositories.Search(data);
// Display results
foreach(var result in results)
{
result.Display();
}
}
Hope this helps you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.