Reputation: 8320
Suppose we have an application (on a server) that has a set of resources: these resources are indexed by name through a dictionary, that is Dictionary<string, Resource> resources
.
The client sends to the server (using WCF) the names of one or more resources (for example, it sends a List<string>
). On the server there may be only a subset of the resources requested by the client, so when a server receives this list, it sends back a list containing only the names of found resources.
I would like to generalize the search criteria that the client sends to the server, so that in future it is easy to extend the application (both client-side and server-side) with a more complex search criteria.
To achieve this goal, I thought to create the ISearchCriteria
interface, so the client should send an object of a class which implements this interface.
public interface ISearchCriteria
{
// the names of the resources which match with the search criteria
ICollection<string> GetCompliantResources();
}
However it seems to me that this solution is not very correct, because the GetComplianceResources
method should interact with the dictionary on the server, but the client should not know anything about this dictionary... I might use the strategy pattern, associating each concrete strategy to the specific search criteria. In this way could separate the control logic from the data (ie. the search criteria).
UPDATE (strategy pattern and DTO)
// Both on the server and on the client
public interface ISearchCriteria
{
// empty
}
// Both on the server and on the client
public class DefaultSearchCriteriaDTO : ISearchCriteria
{
List<string> ResourceNames { get; set; }
List<int> OtherCriteria { get; set; }
}
// Both on the server and on the client
public class MySearchCriteriaDTO : ISearchCriteria
{
string SearchString { get; set; }
}
// On the server.
public interface IStrategy<T> : where T : ISearchCriteria
{
public List<string> Match(T criteria);
}
// On the server
public class DefaultStrategy : IStrategy<T> where T : DefaultSearchCriteriaDTO
{
public List<string> Match(T criteria)
{
// search for resources and returns those found
}
}
Upvotes: 4
Views: 4821
Reputation: 1
See if Criteria Pattern @ Wikipedia can help you! It's a software pattern bases on specification pattern.
Upvotes: 0
Reputation: 156748
Rather than requiring the client to send you a class that you expect to have do things, have them send you a POCO:
public class SearchCriteria
{
List<string> ResourceNames { get; set; }
// Add more properties here in the future as you identify additional criteria
}
As you add properties to the bound POCO, people using an older version of your API may still have their code work if the binding protocol interprets the absence of a property to mean that the property should not be set.
This object that clients send you will not have any logic: it plays the role of a data-transfer object. Your server is responsible for comparing the given resource names with its internal dictionary to determine which of the provided resources are available.
Looking at your intended use of the strategy pattern, I think you're overcomplicating things. For one thing, I don't even know if WCF can bind to different types of parameters depending on what type of object the user tries to send: there are certainly at least some bindings (JSON, e.g.) that won't allow it. Even if it is possible, this approach feels wrong, and that empty interface is producing a serious code smell. I'd say, keep your service interface clear and simple, with well-defined methods and parameter types.
If you expect that users will be searching by a variety of different "strategies", each of which will require a different set of parameters, create a different method for each potential search algorithm (SearchByResourceNames(List<string resourceNames)
, SearchByDomain(int domainId)
, etc.).
On the other hand, if you want the user to be able to mix and match various types of criteria, just use a SearchCriteria
DTO and let the client populate whichever properties they want to search by.
Upvotes: 4
Reputation: 12157
Honestly, I wouldn't implement it until there's a need for it.
As it it right now, you're going to be programming around situations that may never exist. How will you know when you're "done?"
Remeber: YAGNI.
Upvotes: 7
Reputation: 543
I'd create the ISearchCriteria with a method that returns a bool and accepts a Resource as parameter. The ISearchCriteria's method is called for every resource and returns true if you want the resource being included in the return list. You can also implement this using delegates instead of interfaces, something like:
public delegate bool IsValidResource(Resource currentResource);
Upvotes: 0