I've read a couple of articles my Mark Seeman on Dependency Injection, specifically the reasons for avoiding the Service Locator pattern:
- Service Locator is an Anti-Pattern
- Service Locator violates encapsulation
- Service Locator violates SOLID
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