Reputation: 3729
Trying to figure out how to best handle the following scenario:
Assume a RequestContext
class which has a dependency to an external service, such as:
public class RequestContext : IRequestContext
{
private readonly ServiceFactory<IWeatherService> _weatherService;
public RequestContext(ServiceFactory<IWeatherService> weatherService, UserLocation location, string query)
{
_weatherService = weatherService;
...
What sort of dependency should I require in the class that will ultimately instantiate RequestContext
? It could be ServiceFactory<IWeatherService>
, but that doesn't seem right, or I could create an IRequestContextFactory
for it along the lines of:
public class RequestContextFactory : IRequestContextFactory
{
private readonly ServiceFactory<IWeatherService> _weatherService;
public RequestContextFactory(ServiceFactory<IWeatherService> weatherService)
{
_weatherService = weatherService;
}
public RequestContext Create(UserLocation location, string query)
{
return new RequestContext(_weatherService, location, query);
}
}
And then pass the IRequestContextFactory
through constructor injection.
This seems like a good way to do it, but the problem with this approach is that I think it hinders discoverability (devs must know about the factory and implement it, which is not really apparent).
Is there a better/more discoverable way that I'm missing?
Upvotes: 6
Views: 3098
Reputation: 7856
The Factory pattern is a well known, documented, and used method. If you're that concerned about other devs not being up-to-speed, then put a link to wikipedia's factory pattern page in the (xml) documentation in the code.
Also, make sure you name your Factories consisently - Microsoft seem to like the Provider suffix.
Upvotes: 0
Reputation: 233397
The beauty of loose coupling is that we can constantly hide away the previous details.
From the perspective of a consumer of IRequestContext the existence of RequestContext and its dependencies is purely an implementation detail. Because of the Liskov Substitution Principle, the consumer must only deal with IRequestContext:
public class MyClass
{
private readonly IRequestContext reqCtx;
public MyClass(IRequestContext reqCtx)
{
if (reqCtx == null)
{
throw new ArgumentNullException("reqCtx");
}
this.reqCtx = reqCtx;
}
// Implement using this.reqCtx...
}
Only at the application's Composition Root do you need to finally wire everything together. Here's a sketch of a Poor Man's DI approach:
ServiceFactory<IWeatherService> weatherService =
new ServiceFactory<IWeatherService>();
UserLocation location = new UserLocation;
string query = "foo";
IRequestContext reqCtx = new RequestContext(weatherService, location, query);
var mc = new MyClass(reqCtx);
Upvotes: 5