I have some global components I am not sure how to put them in design. Such as:
Settings class: it is interfacing the initial settings of the program, it could be app.config(1way), web.config(1way), hard coded values(1way), or sqldb(2way) behind the scenes.
Language class: it contains different language sets, and again, I could have some resx files(1way), hard coded values(1way) or sqldb(2way) behind it.
First question is, should I make these classes setter properties in dependency injection (I use Windsor):
public ISettings Settings {set;}
public ILanguage Language {set;}
Or should I make them ambient context:
string DoSomethingAndReportIt() {
//do something ...
var param = Settings.Current.SomeParam;
//report it ...
return Language.Current.SomeClass_SomeMethod_Job_Done;
}
I notice there are a few components in .net library that actually use ambient context pattern, e.g. System.Security.Principal, System.Web.ProfileBase, System.Thread.CurrentCulture ...
Do you think it is no harm to make my global classes such as Settings and Language to be ambient context classes? If not, why DI is preferred? Do they take more advantage in unit testing compare to ambient?
Second question is, if DI is better, (I have a feeling that the DI pattern is preferred), what is a good way to proxy the existing ambient classes such as Security.Principal or Profile to follow the DI pattern?
The ambient context is known as an anti-pattern of Dependency Injection, in the sense that offers a way to access a dependency direct or indirectly through static members of a class. To illustrate the ambient context in practice, let's see the following example: class LocationManager { ....
PROPERTY INJECTION is also known as SETTER INJECTION.
In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs.
Property injection is a type of dependency injection where dependencies are provided through properties. Visit the Dependency Injection chapter to learn more about it. Let's understand how we can perform property injection using Unity container. Consider the following example classes.
Ambient context is OK when you need to implement functionality that spans across multiple layers. (In your case you say that the two objects are global) This functionality is known as crosscutting concerns. As you noticed many classes in .NET are implemented as ambient context, like IPrincipal
. In order to get a working version of your implementation of ambient context, you will need to have some default value provided to your Settings
and Language
objects if they are developed as ambient context. My assumption is that you will provide some default implementation of ILanguage
and ISettings
, and considering that you will use them globally they are good candidates for ambient context.
On the other hand, how often do you plan to use those objects that implement these two interfaces? And, is the existence of the two objects crucial, meaning Settings != null
and Language != null
? If you really intend to use them in one or two classes, and/or if the existence of the objects is not really important, you might want to go with the setter injection. The setter injection does not really need a default value, so your object can be null
.
Personally I am not a fan of ambient context. However I would use it if it turns out to be the most acceptable solution. In case of your implementations I would do something like this: because you will need to initialize objects which implement the two interfaces once and in one location only, you could start with the ambient context. If you realize that you are using it in a very small number of locations, think about refactoring it as a setter injection. If the existence of objects is important think about constructor injection implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With