Является ли смешение на основе конструктора и установки на основе инъекций плохим?

У меня есть класс для импорта товаров из CSV файла, который требует около 7 параметров. Это информация, которая определенно необходима импортеру.

Все эти параметры имеют одинаковое время жизни. В конце концов мы должны иметь Неизменяемый объект.

Я был слишком напуган, чтобы перечислить все из них в конструкторе из-за его влияния на читаемость и решил перенести 3 из них на инъекции сеттеров. Но, очевидно, это не изящное решение.

Вопросы:

1) Является ли смешение на основе конструктора и установки на основе инъекций плохой практикой?

2) Как эта конкретная проблема может быть решена?

Я думал о применении рефакторинга "Ввести объект параметров" Мартина Фаулера, но есть проблема с этим.

4 Параметры можно легко перемещать в объект параметров (customerId, projectId, languageId и т.д.) - все целые числа.

Другие 3 параметра - это объект, который я вставляю (требуется для модульных тестов).

Ответы

Ответ 1

Не обязательно плохо смешивать инжекцию конструктора и вложение свойств, но это может быть не так уж и просто. В качестве общей стратегии избегайте Property Injection, поскольку ее гораздо сложнее реализовать правильно (это может показаться противоречивым, но это правда).

Важно понимать, когда использовать каждый шаблон.

  • Конструкция Инъекция должна быть вашим шаблоном инъекции по умолчанию. Он очень прост в реализации и может гарантировать инварианты: назначьте его в поле только для чтения, чтобы обеспечить потребительские инварианты.
  • Вложение свойств может использоваться, когда у вас есть хорошая локальная настройка по умолчанию, но вы хотите следовать Open/Closed Principle и позволяют продвинутым пользователям расширять класс, предоставляя альтернативную реализацию.

Вы никогда не должны применять свойство Injection из-за конструкторской косметики.

Если вам требуется слишком много зависимостей, это признак того, что вы можете нарушать принцип единой ответственности - класс просто пытается сделать слишком много сразу.

Вместо того, чтобы вводить объект Parameter (в противном случае это хорошее предложение), лучшим вариантом является инкапсуляция двух или более зависимостей в службу агрегации, которая организует взаимодействие этих зависимостей.

Представьте, что ваш первоначальный конструктор выглядит так:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)

После применения небольшого анализа вы выясните, что в этом случае IDep1, IDep3 и IDep4 будут использоваться вместе определенным образом. Это позволит вам ввести службу агрегирования, которая инкапсулирует их следующим образом:

public class AggService : IAggService
{
    public AggService(IDep1 dep1, IDep3 dep3, IDep4 dep4)
    {
        // ...
    }

    // ...
}

Теперь вы можете переписать исходный конструктор:

public MyClass(IAggService aggSrvc, IDep2 dep2, IDep5 dep5)

и т.д.

Очень часто, что совокупная услуга оказывается правильной концепцией в ее собственном праве, и внезапно у вас есть более богатый API, чем когда вы начали.