Recently I've noticed myself implementing pattern similar to the one described below. Starting with interface:
public interface IUserProvider
{
User GetUser(UserData data);
}
GetUser method's pure job is to somehow return user (that would be an operation speaking in composite terms). There might be many implementations of IUserProvider, which all do the same thing - return user basing on input data. It doesn't really matter, as they are only leaves in composite terms and that's fairly simple.
Now, my leaves are used by one own them all composite class, which at the moment follows this implementation:
public interface IUserProviderComposite : IUserProvider
{
void RegisterProvider(Predicate<UserData> predicate, IUserProvider provider);
}
public class UserProviderComposite : IUserProviderComposite
{
public User GetUser(SomeUserData data) ...
public void RegisterProvider(Predicate<UserData> predicate, IUserProvider provider) ...
}
Idea behind UserProviderComposite is simple. You register providers, and this class acts as a reusable entry-point. When calling GetUser, it will use whatever registered provider matches predicate for requested user data (if that helps, it stores key-value map of predicates and providers internally).
Now, what confuses me is whether RegisterProvider method (brings to mind composite's add operation) should be a part of that class. It kind of expands its responsibilities from providing user to also managing providers collection. As far as my understanding goes, this violates Single Responsibility Principle... or am I wrong here?
I thought about extracting register part into separate entity and inject it to the composite. As long as it looks decent on paper (in terms of SRP), it feels bit awkward because:
I would be essentially injecting Dictionary (or other key-value map)
...or silly wrapper around it, doing nothing more than adding entires
This won't be following composite anymore (as add won't be part of composite)
What exactly is the presented pattern called? Composite felt natural to compare it with, but I realize it's not exactly the one however nothing else rings any bells. Which approach would you take - stick with SRP or stick with "composite"/pattern? Or is the design here flawed and given the problem this can be done in a better way?