简体   繁体   中英

How do I design a class that would normally be static when I'm using dependency injection?

I have a class that encapsulates a bunch of strings that serve as defaults for app settings that haven't been otherwise explicitly specified by the user.

I'm currently using a plain old class with relevantly-named instance methods—this sort of thing:

class SiteConfigurationConventions : ISiteConfigurationConventions
{
    public String GetConfigurationFileName()
    {
        return "SiteConfiguration.xml"; 
    }
}

It seems that a static class would be more conceptually appropriate (like System.Math ) since these strings won't ever change at run time and no fields are required, but I'm not sure how compatible static classes are with DI. For example, it doesn't seem possible to register a static class with the container so it returns it to constructors asking for it in other objects being resolved by the container.

As it is now, I register

container.RegisterType<ISiteConfiguration, SiteConfiguration>();

So that the requesting constructor gets what it needs:

public SiteGenerator(ISiteConfiguration siteConfiguration)

My design options would seem to be:

  • Refactor to a static class and reference the concrete type directly in my consuming class rather than using constructor injection
  • Leave it as-is (class and instance resolved to an interface), perhaps optionally registering it using the singleton lifetime for the sake of correctness
  • Creatging some kind of facade or factory to hide the static behind. However, for some reason this options just strikes me as silly.

The notion of an "instance" of a class like this seems odd—static seems more conceptually correct. The only reason I'd be making it an instantiable class is to make it more DI friendly. Does that sound OK, or correct? Am I missing something entirely?

Any counsel would be most appreciated. :)

Most DI libraries give you the option to specify that a single instance can be used for all injections (creates a single instance and give that as the answer every time). This is a form of Singleton, and would probably suit your problem well.

For example, using MS Unity library, you would put:

container.RegisterInstance(new SiteConfiguration());

I consider the static keyword to be a form of built-in singleton implementation, while the DI route does much the same thing, but without using the compiler to take care of the details.

OK, after a bit of research, Googling, and thinking, I believe I've arrived at my own conclusions.

The use of static classes is in a sense at odds with the IoC principle and loose coupling that I intend to bake into my architecture. The static modifier is a way of saying that only one implementation can answer a particular purpose, which is at odds with DI generally (loose coupling, programming to interfaces, testability, and all the things that go with that).

Equally, the static modifier is really just a way of telling the compiler we want to restrict the number of instances of a class to one while simultaneously never allowing it to be assigned to a variable (ie, no use of the new operator). If we are to employ IoC, we should be leaving lifestyle management like this up to the composition root, and we're never directly referencing concrete classes (other than FCL classes) this way anyway. So static classes serve little purpose to us.

Therefore, I say leave it as a plain old (non-static) class and apply a singleton lifestyle at the composition root. Unless, of course, you think your would-be static class is unlikely ever to change and that you'll never need to fake it in testing, in which case you could just treat it like a stable dependency (like an FCL class) and exclude it from your normal DI scheme, referencing the concrete class directly in consuming classes.

If you must depend on a third-party class that uses static methods or is itself entirely static that you want to inject as a dependency (and thus be able to substitute for testing, etc., purposes), you should perhaps still create an interface and rely on an instantiable adapter that calls the static methods to get those values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM