Этим вопросом является результат сообщения Jeffery Palermo о том, как обойти разветвленный код и внедрение зависимости http://jeffreypalermo.com/blog/constructor-over-injection-anti-pattern/
В его сообщении у Jeffery есть класс (public class OrderProcessor : IOrderProcessor
) это берет 2 интерфейса на конструкторе. Каждый - блок проверки допустимости IOrderValidator
и IOrderShipper
интерфейс. Его ответвления кода метода только после использования методов на IOrderValidator
взаимодействуйте через интерфейс и никогда ничего не использует на IOrderShipper
интерфейс.
Он предлагает создать фабрику, которая назовет статический метод получить делегата интерфейса. Он создает новый объект в своем пересмотренном коде, который кажется ненужным.
Я предполагаю, что затруднение проблемы, мы используем МОК для создания всех наших объектов независимо, если они используются или нет. Если Вы инстанцируете объекта с 2 интерфейсами и имеете код, который мог бы перейти для не использования одного из них, как Вы обрабатываете его?
В этом примере мы принимаем _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 CreationClosure;
public IOrderShipper GetDefault()
{
return CreationClosure(); //executes closure
}
}
И вот метод, который настраивает эту фабрику во время запуска (global.asax для ASP.NET):
private static void ConfigureFactories()
{
OrderShipperFactory.CreationClosure =
() => ObjectFactory.GetInstance();
}
Я только что опубликовал опровержение поста Джеффри Палермос .
Короче говоря, мы не должны позволять деталям реализации конкретных влияния на наш дизайн. Это было бы нарушено принципу замены Лисива в архитектурном масштабе.
Более элегантное решение позволяет нам сохранить дизайн, представляя предусматривание ленивого загрузки.
Я думаю, что анти-образник здесь - чрезмерное использование интерфейсов.
Я опаздываю поздно для встречи, но несколько быстрых моментов ...
Прилипать к коду разветвлению использования только одной зависимости, есть две ветви для предложения:
Как и кто-то еще, который здесь упомянул здесь, точка состоит в том, чтобы нарушить зависимость от конкретных классов и свободно пару зависимостей, использующих инъекцию зависимости с использованием некоторого контейнера IOC.
Это делает будущий рефакторинг и обмениваться устаревшим кодом гораздо проще в большом масштабе путем ограничения технического долга в будущем. После того, как у вас есть проект возле 500 000 строк кода, с тестами на 3000 единиц, вы узнаете из первых рук, почему IOC так важен.