I am new to DI and I would like to know how DI might be used to help resolve this problem.

If I have an ILatLongLocation which implements a Latitude and Longitude, then given two of these I can produce a Distance using a variety of algorithms, but I can also reasonably pick one of these as the "best" algorithm at design-time without losing any sleep.

However, since users will rarely input physical coordinates, I may need to instead compare by zip codes or something similar.

Now, in order to resolve zip codes to coordinates, I could apply a naive algorithm that uses string concatenation, etc to do a rough guess as to the physical coordinates, I could pick a random set of coordinates, etc. But in all likelihood, I will need to resolve the zip codes by using some sort of database mapping zip codes to coordinates.

So being new to DI, I would like to know if the following is a reasonable application of DI and/or if I am overthinking it.

ILocatable has ILatLongLocation

ILocatableProvider<T> : ILocatable has a T RawLocatable and can return an ILatLongLocation.

IZipCodeLocatableProvider : ILocatableProvider<string> has a string RawLocatable and returns an ILatLongLocation.

NaiveZipCodeLocatableProvider is an implementation that just uses patterns in zip codes that are well-known to provide a best-effort guess as to the coordinates.

DbZipCodeLocatableProvider is an implementation that uses a database (maybe through a DbContext or somehow else) to return the coordinates.

Now DbZipCodeLocatableProvider itself must depend on some sort of repository or context or connection or something to access a database (unless it is literally hard-coded)... so then this means I need to have a DbContext or something similar... here is where I get lost.

Am I thinking about this the right way? Is this a legitimate scenario for dependency injection? And how do I discriminate between, say different connection strings vs different strategies altogether for resolving zip codes to coordinates?

Edit: ...and don't forget about WebServiceZipCodeLocatableProvider ... there's another (realistic) option.

  • Suggested rephrase: How should one implement the interfaces and dependency-injection for a geocoding client, which aggregates from various service providers (implementations) and supports interactive disambiguation with the human user among other geocoding use-cases? – rwong Jun 30 '14 at 10:14
  • Another aspect to consider is the asynchronous and time-consuming nature of the request. If requests are made simultaneously to multiple geocoding services, then their responses will usually arrive at different times. Will these responses be immediately made available to the application code (GUI), or will they be batched together until timeout? – rwong Jun 30 '14 at 10:24
  • @rwong, couldn't quite fit that in the title but I tried... – tacos_tacos_tacos Jun 30 '14 at 10:27
  • @rwong, since this would mainly be used in the context of filtering and sorting (it is not the primary purpose of my application but a necessary aspect), the filtering and sorting would have to wait on these to finish, but that is already an asynchronous deal... you apply the filter/sort in the UI, the results section gets blocked with a spinner, so... is that addressing your question? – tacos_tacos_tacos Jun 30 '14 at 10:30
  • @rwong as for using different providers simultaneously, I don't know whether that would necessarily be the case. But I could see this scenario: calculate distance using all three simultaneously... wait for X seconds, and rank the providers by reliability. So if either database or web service comes back first, then go with that result. Otherwise, if X seconds elapses and neither of those two have a result, go with the naive strategy. – tacos_tacos_tacos Jun 30 '14 at 10:32

I would only implement the dependency-injection for a geocoding client that aggregates different coordinate provider implementations if you either

  • have more than one provider (i.e. location based on ip-adress instead of zip code)
  • or do Test-driven_development.

For me your design looks over-complicated.

I have implemented something similar for android using Test-driven_development and all i needed was

  • a LatLongLocationCalculationService that can process ILatLongLocation (i.e. calculates distance between to locations)
  • a ZipCodeLatLongAdapter that lets Zip-codes appear as ILatLongLocation.

An implementation detail for the ZipCodeLatLongAdapter is that it looks up the location of a zip-code from the database.

    double Latitude;
    double Longitude;

    ILatLongLocation GeoCoordinate;

Ok, looks sensible so far. I would probably change the names a little, but that's just preference.

ILocatableProvider<T> : ILocatable

You lost me here. Lets maybe specify in the simplest terms what you need the service to perform. From what I can understand, you want a service to take in a zip code, and return you an ILatLongLocation. To put that in code terms.

    ILatLongLocation GetGeoCoordsFromZip(string zip);

This doesn't return ILocatables, because ILocatables are themselves the containers of ILatLongLocations. This service would be used by whatever process is creating the ILocatable when the geo-coordinates must be derived from a zip code.

ILocatable objectWithGeoCoordinates = new GeoCoordinateWrapperThingy();
objectWithGeoCoordinates.GeoCoordinate = injectedIZipToGeoCoordsService.GetGeoCoordsFromZip(aZipCode);

The rest of what you mention, especially the DB context part, seems due to you wanting to encapsulate the creation of ILocatables along with the creation of ILatLongLocations. But to create an ILocatable from a zip code in the first place, you first need some service to derive that.

At whatever point you're taking your object that has a zip code, and want to convert it over to a version of itself that implements ILocatable, whatever is doing that conversion would need the IZipToGeoCoords service constructor injected into it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.