Этот вопрос является результатом сообщения Джеффри Палермо о том, как обойти разветвленный код и инъекцию зависимости http://jeffreypalermo.com/blog/constructor-over-injection-anti-pattern/
В своем посте Jeffery имеет класс (public class OrderProcessor : IOrderProcessor
), который имеет два интерфейса в конструкторе. Один из них - это валидатор IOrderValidator
и IOrderShipper
. Его ветки кода метода только после использования методов на интерфейсе IOrderValidator
и никогда ничего не используют в интерфейсе IOrderShipper
.
Он предлагает создать factory, который вызовет статический метод для получения делегата интерфейса. Он создает новый объект в своем рефакторированном коде, который кажется ненужным.
Я предполагаю, что суть проблемы в том, что мы используем IoC для создания всех наших объектов независимо от того, используются они или нет. Если вы создаете экземпляр объекта с двумя интерфейсами и имеете код, который может веткиться, чтобы не использовать один из них, как вы его обрабатываете?
В этом примере мы предполагаем, что _validator.Validate(order)
всегда возвращает false, а метод IOrderShipper.Ship()
никогда не вызывается.
Оригинальный код:
public class OrderProcessor : IOrderProcessor
{
private readonly IOrderValidator _validator;
private readonly IOrderShipper _shipper;
public OrderProcessor(IOrderValidator validator, IOrderShipper shipper)
{
_validator = validator;
_shipper = shipper;
}
public SuccessResult Process(Order order)
{
bool isValid = _validator.Validate(order);
if (isValid)
{
_shipper.Ship(order);
}
return CreateStatus(isValid);
}
private SuccessResult CreateStatus(bool isValid)
{
return isValid ? SuccessResult.Success : SuccessResult.Failed;
}
}
public class OrderShipper : IOrderShipper
{
public OrderShipper()
{
Thread.Sleep(TimeSpan.FromMilliseconds(777));
}
public void Ship(Order order)
{
//ship the order
}
}
Реализованный код
public class OrderProcessor : IOrderProcessor
{
private readonly IOrderValidator _validator;
public OrderProcessor(IOrderValidator validator)
{
_validator = validator;
}
public SuccessResult Process(Order order)
{
bool isValid = _validator.Validate(order);
if (isValid)
{
IOrderShipper shipper = new OrderShipperFactory().GetDefault();
shipper.Ship(order);
}
return CreateStatus(isValid);
}
private SuccessResult CreateStatus(bool isValid)
{
return isValid ? SuccessResult.Success : SuccessResult.Failed;
}
}
public class OrderShipperFactory
{
public static Func<IOrderShipper> CreationClosure;
public IOrderShipper GetDefault()
{
return CreationClosure(); //executes closure
}
}
И вот метод, который настраивает этот factory во время запуска (global.asax для ASP.NET):
private static void ConfigureFactories()
{
OrderShipperFactory.CreationClosure =
() => ObjectFactory.GetInstance<IOrderShipper>();
}