1

I have an interface:

public interface IHHSDBUtils
{
    void SetupDB();

    bool TableExists(string tableName);
    . . .

...that has multiple implementers:

public class SQLiteHHSDBUtils : IHHSDBUtils
public class SQCEHHSDBUtils : IHHSDBUtils
public class FlatfileHHSDBUtils : IHHSDBUtils
public class TestHHSDBUtils : IHHSDBUtils

I want to be able to specify which implementer is going to be used from a globally accessible spot, such as:

public static class HHSConsts
{
    public static IHHSDBUtils hhsdbutil = SQLiteHHSDBUtils;

...and then call it like so from anywhere in the app:

private HHSDBUtils hhsdbutils { get; set; }
. . .
hhsdbutils = new HHSConsts.hhsdbutil;
hhsdbutils.SetupDB();

Is this possible? I get, "'SQLiteHHSDBUtils' is a 'type' but is used like a 'variable' with its assignment to hhsdbutil above.

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • 3
    If you were using dependency injection (why aren't you?) you could tell the di container which implementation to use in the composition root. The way it's currently written you can just new it up public static IHHSDBUtils hhsdbutil = new SQLiteHHSDBUtils(); – reggaeguitar Dec 01 '14 at 19:54
  • You could use a service locator which resolves the correct instance based upon for example a config file (though, this is also seen as an anti-pattern). Or else you could look into a IoC container to configure which instance to resolve. – Styxxy Dec 01 '14 at 19:54
  • @reggaeguitar: DI seems to me like sort of a monstrosity; it reminds me of forcing a trapezoidal peg into a spherical aperture. It's hard to understand, and thus maintain, and it requires a 3rd-party "Container" to make it work well. That to me indicates it's a bit unnatural, like sticking Cyrano de Bergerac's nose onto Dr. Frankenstein's monster. IOW: I'm trying to avoid DI. – B. Clay Shannon-B. Crow Raven Dec 01 '14 at 21:32
  • 2
    With power comes complexity, I can't tell you what you should and shouldn't do, but I can say that DI has saved me probably hundreds of hours in my career. Buy Dependency Injection in .NET (book by Mark Seemann) and read it and you will thank me. Imagine anytime you need a dependency in a class you just add it to the ctor signature and it works! It's very nice to have. Side note: it's near impossible to write unit tests without dependency injection and it leads to much cleaner design and architecture. – reggaeguitar Dec 01 '14 at 21:51
  • @reggaeguitar: Well, maybe you have a point (I do, that's why I wear a sombrero); but this is a Windows CE project, which I doubt would be twistable to use DI in. The stripped-down version of .NET it uses quakes on seeing its own shadow, gescwhweige denn so einen Schlammassel. – B. Clay Shannon-B. Crow Raven Dec 01 '14 at 22:27
  • The thing I don't like about DI (and other fancy-pants whiz-bang code elegantizations) is that I can't look at it and grok what's going on - what is being injected in this situation and that scenario. "My way" is perhaps the plodding Winnie-the-Pooh, whoop-de-doo way, but at least I can follow its logic and flow. IOW: Don't let the robots take over! – B. Clay Shannon-B. Crow Raven Dec 02 '14 at 00:08

1 Answers1

2

You could do a poormans Factory implementation by creating an enum for each type and have a static factory method that creates the type for you. I stay as close to your current code snippets as possible.

public enum HHSDBUtilsTypes 
{
    Sqllite,
    SQCE,
    Flatfile,
    Test
}

public static class HHSConsts
{
    private const string implementation = HHSDBUtilsTypes.Sqllite; // you might read this from the config file

    public static IHHSDBUtils GetUtils()
    {
         IHHSDBUtils impl;
         switch(implementation)
         {
            case HHSDBUtilsTypes.Sqllite:
               impl = new SQLiteHHSDBUtils();
            break;
            case HHSDBUtilsTypes.SQCE:
               impl = new SQCEHHSDBUtils();
            break;
            case HHSDBUtilsTypes.Sqllite:
               impl = new FlatfileHHSDBUtils();
            break;
            default:
               impl = new TestHHSDBUtils();
            break;
         }
         return impl;
    }
}

And you would use it like so:

private IHHSDBUtils hhsdbutils { get; set; }
//. . .
hhsdbutils = HHSConsts.GetUtils();
hhsdbutils.SetupDB();

An other option is to use Activator.CreateInstance.

 const string fulltypename = "Your.Namespace.SQLiteHHSDBUtils"; // or read from config;
 hhsdbutils = (HHSDBUtils) Activator.CreateInstance(null, fulltypename).Unwrap();

Make sure to test and measure performance, specially if you need to instantiate a lot of types often via any of these methods.

If you want more control use a Dependency Injection/Inversion of Control framework like:

Be aware though that all of these frameworks bring in their own powerfull features but also added complexity. If you feel you have to select a framework take maintainability and learnability as a dominant requirement.

Here is some extra documentation on DI

rene
  • 41,474
  • 78
  • 114
  • 152
  • I've used Castle Windsor and find it awkward and hard to grok; what would it be like after somebody else has to maintain it, or even myself after not looking at the code for awhile: a nightmare! – B. Clay Shannon-B. Crow Raven Dec 01 '14 at 21:33
  • OK, I didn't use it my self but let me add that as a warning – rene Dec 01 '14 at 21:35
  • You can configure a whole application in 2 lines using Castle Windsor like so `var container = new WindsorContainer(); _container.Register(Classes.FromThisAssembly() .InNamespace("YourNamespace") .WithService.DefaultInterfaces() .LifestyleTransient());` As long as you name classes the same as the interface (minus the leading 'I') this will work. DI really isn't that hard – reggaeguitar Dec 01 '14 at 21:56
  • @reggaeguitar sure, but your example made me smile... if you're over the top of the learning curve even php becomes easy... – rene Dec 01 '14 at 22:02