I know there is all this talk about having only one composition root that set all your dependencies and that you should always prefer constructor injection to other types, but sometimes it just doesn't make any sense for me. Here is my pseudo code :
public class FakeModel
{
private FakeDependency Dependency = ServiceLocator.Get<FakeDependency>();
public string Name { get; private set; }
public FakeModel(string name)
{
Name = name;
}
public void UpdateName(string name)
{
Dependency.RandomAction();
Name = name;
}
}
Special considerations :
- FakeModel and FakeDependency sit in a class library project that is reused my many other projects.
- All the other projects using this class library doesn't know, and shouldn't even know, that FakeDependency exists.
- There will always be only one (+test) implementation of FakeDependency.
- The only reason to replace the FakeDependcy is to run tests that only test the class library.
Would you rewrite this code differently, or it makes sense considering the requirements?
EDIT
There seems to be some confusion about the dependency, the service locator and how to use the class library. Think about the model as the public interface of this class library. Everything else is hidden from other projects, is undocumented and subject to changes anytime. You should not ever used any other methods than those define by the model.
About the service locator; it lives inside the class library project. It's only purpose is to make it possible to test the class library and absolutely not to inject new dependencies into this library. If I wanted to make it possible to replace the dependency I would of course have used constructor injection like that public FakeModel(string name, FakeDependency dependency)
but that is not the case.
Then how do you use this class library currently? Just like that :
public void Test()
{
var model = new FakeModel("MyName");
model.UpdateName("NewName");
}
The class library should be self contained. Maybe using the word "dependency" is confusing as it's not something that you need to provide to the class library.
1 Answer 1
Yes I would rewrite it.
Edit: new code based on your expanded comments and question:
[assembly: InternalsVisibleTo("TestAssembly")]
public class FakeModel
{
private IFakeDependency dependency;
public string Name { get; private set; }
public FakeModel(string name)
{
Name = name;
this.dependency = new FakeDependency();
}
//use this constructor in tests
internal FakeModel(string name, IFakeDependency dependency)
{
Name = name;
this.dependency = dependency;
}
public void UpdateName(string name)
{
dependency.RandomAction();
Name = name;
}
}
-
I think the question is then should
FakeDependency
be bound in the application composition point in the project referencing this one, or in the project which it lives? From my understanding, OP is saying that the former is the standard way of doing this, but has the issues that it means that nowFakeDependency
has to be public and known about by other projects. And also that this same binding has to be repeated in lots of projects.Ben Aaronson– Ben Aaronson06/04/2015 16:57:39Commented Jun 4, 2015 at 16:57 -
-
@BenAaronson Yup you got it. In fact, FakeDependency should never be used outside the class library project. The Model provides the public interface of the library project and all the other stuffs should stay hidden.Gudradain– Gudradain06/04/2015 17:11:19Commented Jun 4, 2015 at 17:11
-
Ewan, the service locator in the example is a part of the class library project. And no, I don't want to make it easy to change in the sense that you can provide another implementation if you use that class library. If you exclude the tests, there is and should only be one implementation. And all other project using this library shouldn't even bother knowing it.Gudradain– Gudradain06/04/2015 17:13:20Commented Jun 4, 2015 at 17:13
-
I think you will end up exposing it either way. maybe you could add your ServiceLocator code?Ewan– Ewan06/04/2015 17:17:54Commented Jun 4, 2015 at 17:17
Explore related questions
See similar questions with these tags.
FakeDependency
lives. That would work just as well with constructor injection.FakeDependency
can expose a module class with a method likeConfigureBindings(IKernel kernel)
(or whatever type your IOC container uses). Then in the folder where you do your composition, in your application entry project, you can call that method