andreialecu
andreialecu

Reputation: 3729

Dependency injection and factory

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

Answers (2)

kͩeͣmͮpͥ ͩ
kͩeͣmͮpͥ ͩ

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

Mark Seemann
Mark Seemann

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

Related Questions