Принцип инверсии зависимостей гласит:
Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
Другими словами, каждый модуль, от которого зависит (то есть все, кроме модулей точки входа в вашем приложении), должен быть абстрагирован. В противном случае высокоуровневый модуль должен будет напрямую зависеть от низкоуровневого модуля, что приведет к нарушению DIP.
Количество реализаций абстракции не имеет значения для DIP, поскольку его цель — сделать модули устойчивыми к изменениям. Без абстракций было бы невозможно легко изменять реализации или добавлять сквозные аспекты без необходимости изменять или перекомпилировать высокоуровневый компонент.
Однако, если вы обнаружите, что определяете множество абстракций только с одной реализацией, вы нарушаете Принцип повторного использования абстракции, как уже заявил Марк Симанн в статье, на которую вы ссылаетесь:
Наличие только одной реализации данного интерфейса — это запах кода.
Однако это означает не то, что вы вообще не должны определять интерфейсы, а то, что вам нужно хорошенько взглянуть на свой дизайн и определить классы, связанные поведением. Эти связанные классы часто могут быть помещены за одну и ту же общую абстракцию (общий интерфейс), и это не только позволяет повторно использовать абстракцию, но и делает применение сквозных задач детской игрой.
Вот несколько предложений по функциональности, которую вы можете разместить за одной и той же общей абстракцией:
- ICommandHandler‹TCommand> для классов, которые вносят изменения в систему от имени пользователя (варианты использования).
- IQueryHandler‹TQuery, TResult> в качестве абстракции для классы, которые запрашивают базу данных (или файловую систему, веб-службу, что угодно) и возвращают данные.
IValidator<T>
для классов, которые проверяют сообщения об ошибках проверки обратно пользователю
ISecurityValidator<T>
для классов, которые проверяют, разрешено ли пользователю выполнять определенную операцию.
IAuthorizationFilter<T>
для классов, которые позволяют применять безопасность на основе строк на основе разрешений и ролей пользователя.
IEventHandler<T>
для классов, которые реагируют на определенное бизнес-событие.
Это всего лишь несколько примеров абстракций. Это сильно зависит от приложения и дизайна, какие общие абстракции вы получите.
Приложения, которые я пишу, используют эти общие абстракции, и эти приложения имеют всего несколько интерфейсов с одной реализацией. От 90% до 98% модулей в системе реализуют одну из этих общих абстракций (немного в зависимости от размера приложения; чем больше приложение, тем выше процент).
Эти общие абстракции упрощают регистрацию всех реализаций в одной строке кода в вашей DI-библиотеке (или, по крайней мере, если вы используете .NET), но, что более важно, как я уже говорил ранее, применение сквозных задач становится очень простым. . Например, не внося радикальных изменений в приложение, вы можете запускать варианты использования в транзакции базы данных или применять механизм повторных попыток взаимоблокировки. Или вы можете применить кеширование запросов, не внося радикальных изменений во все приложение.
person
Steven
schedule
28.02.2015