A class being dependant on another class is not uncommon. The dependency can be solved in a multitude of ways, but most common is passing references through the constructor.
However,
when passing references through the constructor you are forcing yourself to
consider the order of creating the objects – i.e. A has to be new’ed before B,
if B is dependent on A. This was something I’d like to not have to worry about.
Basically I wanted to be allowed being lazy.
First let
me provide you with a little insight into the design of this application that
is essentially an implementation of a component based system. (See: Mick West -
“evolve your hierarchy”)
Everything
revolves around Behaviors. These are exactly that by exposing very specific
functionality. Next there’s the BehaviorGroups; behaviors are associated with
groups, and thus groups make up a combination of different functionalities.
Often a
behavior is dependent on another behavior, and this is exactly the problem I’m
presenting a solution to in this post.
To mark a
behavior type as a dependency for another behavior, you simply place the
BehaviorDependency tag on a reference holder and it will be handled
automatically. It reads like this:
[BehaviorDependency]
AnotherBehavior anotherBehavior;
Likewise, you can specify dependencies across the system – i.e. behaviors that are associated with other groups.
[BehaviorDependency(Group = “Another Group”)]
AnotherBehavior anotherBehavior;
Essentially
both of these blocks represent the same action:
- Search group for association with behavior type
- Found
- Inject reference to the object
- Not Found
- Instantiate behavior, associate it with the group and inject reference to the object
The
behavior itself is responsible for searching and finding fields marked with the
dependency attribute. This is handled in the base-class, though, so code-wise
there is little involvement required.
A more contextual
example:
public class SomeBehavior : Behavior
{
[BehaviorDependency]
AnotherBehavior anotherBehavior;
public override void Initialize()
{
base.Initialize();
// AnotherBehavior has now been associated with this behavior’s group, and
// anotherBehavior has been injected with the reference to the newly created
// object
}
}
A few
problems do arise, however. The most prominent one being that when a behavior
is marked as a dependency it is assumed that this particular behavior
implements an empty constructor. This is due to the instantiation of the
behavior under the circumstance that the behavior has not yet been associated
with the group. A minor annoyance if kept in mind and you simply code around
it. The problem could possibly be solved using some further attribute magic,
though.
Secondly,
the references will not be injected until Initialize(). This effectively rules
out using the constructor for anything that involves the dependencies. Again,
not a huge problem when kept in mind.
All in all,
I much prefer having an automatic way of doing this – and come on, you can’t
say it isn’t just a tiny bit pretty to read.