patterncsharpMinor
Handle static objects using custom adapter
Viewed 0 times
objectshandlecustomadapterusingstatic
Problem
I have read some articles discussing about why static is bad, some of them refering static as not-testable, non-mockable, has state (non-stateless) and everything else.
However I have encountered some cases where I am forced to use static implementation, such as:
Up until now I have handle those static methods using custom adapters (correct me if I misuse the term adapter here, or maybe it is better for provider), such as:
Then the consumer will use the adapter like:
I believe that this way I can get the benefits:
However due to inexperienced in design, I am still wondering about:
In this case I want to make sure that my application is testable, maintainable dan extendable. I believe performance is not effecting too much here, so it can be ignored.
Any kind of thoughts will be appreciated
However I have encountered some cases where I am forced to use static implementation, such as:
- During using HttpContext.Current in Asp.Net, as well as Session
- The HttpContext and Session sometimes contains configurations, which is needed to do some validations
- Accessing some static objects in framework or third-party component
- Maybe there are other situation where I don't yet encountered
Up until now I have handle those static methods using custom adapters (correct me if I misuse the term adapter here, or maybe it is better for provider), such as:
public class ConfigurationAdapter : IConfigurationAdapter
{
public string CurrentUsername
{
get
{
return HttpContext.Current.User.Identity.Name;
}
}
}Then the consumer will use the adapter like:
public class ConfigurationConsumer : IConfigurationConsumer
{
public ConfigurationConsumer(IConfigurationAdapter adapter)
{
_adapter = adapter;
}
private readonly IConfigurationAdapter _adapter;
public void DoSomething()
{
string userName = _adapter.CurrentUsername;
}
}I believe that this way I can get the benefits:
- The adapter can be replaced by other implementation
- The adapter can be mocked
- The consumer does not directly dependent on HttpContext
However due to inexperienced in design, I am still wondering about:
- Does this kind of implementation can really decouple the consumer with the static object?
- Will it provide any problem in the future?
- Is there any better design or pattern than this?
In this case I want to make sure that my application is testable, maintainable dan extendable. I believe performance is not effecting too much here, so it can be ignored.
Any kind of thoughts will be appreciated
Solution
I see no problem in such wrappers except they are kinda cumbersome to write. They provide a good way to decouple your code not only from static objects, but from the all the objects you cannot mock too (for example, sealed classes from 3rd party libraries). I use that kind of adapters myself and have little problem with them. It is important to have these classes as simple as possible (so that you don't need to test them) and only expose properties and methods you realy need.
Update: ctrucza suggests using a service locator in his answer. While it's a good solution when your class has many dependencies which leads to many constructor parameters, it makes unit-testing your class a little harder.
If you add some new dependency into your class and resolve it with some generic service locator's method then your code (including unit tests and production code) will compile just fine. You only realize that something is wrong when your working unit-tests will suddenly fail with null reference exception, or some other resolution exception your service locator provides. The constructor injection, on the other hand, gives you a clear knowledge of what dependencies a class using and if you miss some constructor parameter in your tests, the compiler will tell you.
One more thing. If you have a dozen dependencies in your class, may be the design of the class is wrong and refactoring is needed. I think that's really good indicator, which will be hidden if you are using a service locator pattern.
Update: ctrucza suggests using a service locator in his answer. While it's a good solution when your class has many dependencies which leads to many constructor parameters, it makes unit-testing your class a little harder.
If you add some new dependency into your class and resolve it with some generic service locator's method then your code (including unit tests and production code) will compile just fine. You only realize that something is wrong when your working unit-tests will suddenly fail with null reference exception, or some other resolution exception your service locator provides. The constructor injection, on the other hand, gives you a clear knowledge of what dependencies a class using and if you miss some constructor parameter in your tests, the compiler will tell you.
One more thing. If you have a dozen dependencies in your class, may be the design of the class is wrong and refactoring is needed. I think that's really good indicator, which will be hidden if you are using a service locator pattern.
Context
StackExchange Code Review Q#25161, answer score: 6
Revisions (0)
No revisions yet.