Lately, I have invested my efforts into learning and understanding DI. Now that I'm growing more fluent with it, some other concerns come up.
Shall list members be injected into domain model?
In the famous example of Ninject, the idea as I see it is:
public class Warrior {
public Warrior(IWeapon weapon) { this.weapon = weapon; }
public void Attack() { weapon.Hit(); }
}
public Archer : Warrior {
// Here, the weapon would be bound to a bow.
public Archer(IWeapon weapon) : base(weapon) { }
}
public Ninja : Warrior {
// On the contrary, the weapon would here be bound to a katana.
public Ninja(IWeapon weapon) : base(weapon) { }
}
Hence contextual binding to define what weapon should be created depending on what the IWeapon
is injected into.
I understand that injecting a DAO into my model would be implementing the Active Record design pattern, which is considered somehow an anti-pattern by some people. Others would prefer POCOs as domain objects, simple data representation, which is not following the rules of DDD.
Back to my concern, I would say that Warrior
, Archer
and Ninja
are all part of my domain model.
Now, what if my model has an IList<T>
instead of a IWeapon
? Would DI be of any use, or would it become useless?
public class MyClass {
public MyClass(IList<MyOtherClass> myOtherClasses) {
MyOtherClassesA = myOtherClasses.OfType<MyOtherClassA>().ToList();
MyOtherClassesB = myOtherClasses.OfType<MyOtherClassB>().ToList();
}
public IList<MyOtherClassA> MyOtherClassesA { get; protected set; }
public IList<MyOtherClassB> MyOtherClassesB { get; protected set; }
}
- Am I pushing it too far?
- Am I missing something?
EDIT
No, do inject them! But don't inject one list of a base type, which you then split by derived types.
Let's put ourselves in the context of Scrum and a Sprint.
In a Sprint, the Development Team may have Bugs, Impediments, Tasks and UserStories.
All of these have a Title and a Description, plus some other properties specific to each type. Let's make an abstract class called Artifact (not ScrumArtifact).
Artifact
public abstract class Artifact {
public string Description { get; set; }
public string Title { get; set; }
}
Bug
public class Bug : Artifact {
public string Resolution { get; set; }
}
Impediment
public class Impediment : Artifact {
}
Task
public class Task : Artifact {
public float EstimatedTime { get; set; }
public float RealTime { get; set; }
}
UserStory
public class UserStory : Artifact {
public string AcceptanceCriteria { get; set; }
public int BusinessValue { get; set; }
public int Complexity { get; set; }
public IList<Impediment> Impediments { get; protected set; }
public IList<Task> Tasks { get; protected set; }
}
Here, I have a UserStory
which "depends" on two lists: Impediments
and Tasks
.
So I should have the constructor of UserStory
taking two lists as follows.
public UserStory(IList<Impediment> impediments, IList<Task> tasks) {
Impediments = impediments;
Tasks = tasks;
}
And my unit test:
[TestFixture]
public class UserStoryTests {
[Test]
public void ImpedimentsShouldBeInitializedByDefault() {
userStory.Impediments.Should().NotBeNull().And.BeOfType<IList<Impediment>>();
}
public void TasksShouldBeInitializedByDefault() {
userStory.Tasks.Should().NotBeNull().And.BeOfType<IList<Task>>();
}
[TestFixtureSetUp]
public void UserStorySetUp() {
impediments = new Mock<IList<Impediment>>();
tasks = new Mock<IList<Task>>();
userStory = new UserStory(impediments.Object, tasks.Object);
}
private Mock<IList<Impediment>> impediments;
private Mock<IList<Task>> tasks;
private UserStory userStory;
}
The problem comes with the Sprint
. The Sprint
rather require four lists, and I find it too much of objects to inject for clarity and readability. It is said, if I'm not mistaken, that a class with too much dependencies might break the Single Responsibility Principle. Though I'm not breaking the SRP
even with the Sprint
class, I feel quite uncomfortable with injecting four different lists. I thought I could use polymorphism to inject one list which would contain them all, since after all they are all basically Artifact
s.
Perhaps shall I simply consider using the AbstractFactory
pattern so that my four lists get initialized properly as expected, and I would only have to inject one single factory class which single responsibility consist of creating lists?