DivineInject.GitHub.io

View the Project on GitHub DivineInject

Rich Domain Objects

One of the big failings of many DI frameworks is they force separation of behaviour from state. This results in a sea of "NounVerbers" — OrderManager, OrderProcessor, OrderValueWithTaxAddedCalculator etc etc. While there are very good reasons to do this sometimes, most DI frameworks don't support the creation of objects that have both state and dependencies at all — DivineInject does.

By creating an object that has both state and behaviour you can encapsulate behaviours of that object with methods. This makes code easier to understand and easier to test. Taken too far, you end up with god-classes that do everything; too far the other way, and you have an anemic domain model and behaviour introduced through a sea of hard-to-name global, static, methods (dependencies).

User Example

Continuing on from the user scope example we created previously, we will add a user id. First, we introduce the new id into the User class:

internal class User
{
    private readonly Guid _userId;
    private readonly IOrdersService _ordersService;

    public User(Guid userId, IOrdersService ordersService)
    {
        _userId = userId;
        _ordersService = ordersService;
    }
}

Second, we add the id to the user factory. Since the id isn't a dependency DivineInject won't pass it in, it must come from calling code:

internal interface IUserFactory
{
    User Create(Guid id);
}

If we were to hand-code our user factory class, it would look like this (as before, this is just for illustration):

internal class DivineInjectUserFactory : IUserFactory
{
    public User Create(Guid id)
    {
        // DON'T DO THIS - just an example
        var ordersService = DivineInjector.Current.Get<IOrdersService>();
        return new User(id, ordersService);
    }
}

Our factory binding, however, is entirely unchanged:

DivineInjector.Current
    .Bind<IUserFactory>().AsGeneratedFactoryFor<User>();

DivineInject is smart enough to associate the the Guid parameter passed in on the factory interface method with the Guid constructor argument; the second constructor argument, the dependency, is passed in by DivineInject — exactly as in the hand-rolled version.

We can now use our updated user factory:

internal class LoginService
{
    private readonly IUserFactory _userFactory;
    private readonly IAuthenticationService _authenticationService;

    public LoginService(IUserFactory userFactory,
                        IAuthenticationService authenticationService)
    {
        _userFactory = userFactory;
        _authenticationService = authenticationService;
    }

    public User Login(string username, string password)
    {
        Guid userId;
        if (!_authenticationService.TryAuthenticate(username, password, out userId))
            return null;
        return _userFactory.Create(userId);
    }
}

We have now created a rich domain object (User), which has both state (userId) and a dependency (IOrdersService). Our rich domain object can now introduce methods which take advantage of state and dependencies to provide a logical model of users in our domain. Or we may use it as a factory for other classes, to avoid the User class becoming god-like (e.g. IUserOrdersService).