mardi 27 octobre 2015

DI composition root: how does it ensure compile-time resolution checking

I've read a couple of articles my Mark Seeman on Dependency Injection, specifically the reasons for avoiding the Service Locator pattern:

Basic idea behind Service Locator being problematic is that it can fail at runtime:

public class OrderProcessor : IOrderProcessor
{
    public void Process(Order order)
    {
        var validator = Locator.Resolve<IOrderValidator>();
        if (validator.Validate(order))
        {
            var shipper = Locator.Resolve<IOrderShipper>();
            shipper.Ship(order);
        }
    }
}

var orderProcessor = new OrderProcessor();

// following line fails at compile time if you 
// forget to register all necessary services - and
// you don't have a way of knowing which services it needs

orderProcessor.Process(someOrder);

But this means that the Composition Root must not only resolve all dependencies at startup, but actually instantiate the entire object graph, or otherwise we still wouldn't know it all the necessary dependencies have been registered:

private static void Main(string[] args)
{
    var container = new WindsorContainer();
    container.Kernel.Resolver.AddSubResolver(
        new CollectionResolver(container.Kernel));

    // Register
    container.Register(
        Component.For<IParser>()
            .ImplementedBy<WineInformationParser>(),
        Component.For<IParser>()
            .ImplementedBy<HelpParser>(),
        Component.For<IParseService>()
            .ImplementedBy<CoalescingParserSelector>(),
        Component.For<IWineRepository>()
            .ImplementedBy<SqlWineRepository>(),
        Component.For<IMessageWriter>()
            .ImplementedBy<ConsoleMessageWriter>());

    // Everything must be resolved AND instantiated here
    var ps = container.Resolve<IParseService>();
    ps.Parse(args).CreateCommand().Execute();

    // Release
    container.Release(ps);
    container.Dispose();
}

How feasible is this in a real world application? Does this really mean you are not supposed to instantiate anything anywhere outside the constructor?

Aucun commentaire:

Enregistrer un commentaire