Есть ли смысл в интерфейсе, если его реализует только один класс?
Глядя на (зрелую) кодовую базу на моей новой работе, есть интерфейс, и только один класс реализует его (насколько я могу судить). Можно / нужно избавиться от интерфейса?
9 ответов
Ни за что! Он не имеет никаких вредных последствий, и однажды кто-то может поменять реализацию без необходимости рефакторинга тонны кода.
В дополнение к уже полученным хорошим ответам - если в какой-то момент в будущем этот класс нужно будет смоделировать для целей тестирования, сделать это будет намного проще, когда уже есть доступный интерфейс!
Так как вы упомянули зрелую базу, я бы хотел привести еще один пример из реальной жизни: сессия Hibernate.
Session - это интерфейс, реализованный только одним классом: SessionImpl. Однако, если вы использовали hibernate в прошлом или читали его исходный код, вы, вероятно, заметили, как Session используется везде вместо SessionImpl.
Это неправильный дизайн? Определенно нет. Это называется "принцип замещения" или "программирование на интерфейсы". Это означает, что, используя интерфейс вместо реализации, вы можете расширить свой код без каких-либо усилий, просто создав соответствующие экземпляры новых классов, но всегда используя интерфейс. Будет ли все еще неправильно, если никто не создаст новый класс, реализующий Session? Нет, все еще не так.
Мои два цента.
Не сегодня. Через шесть месяцев после того, как проект вырос в десять раз по сложности? Кто знает. На ваш взгляд, если это унаследованный код, то интерфейс, который реализован один раз, не имеет большого значения, но также нет смысла проходить рефакторинг, связанный с его удалением. "Если это работает, не исправляйте это".
Я бы сказал, что это зависит, но в большинстве случаев интерфейс является хорошей идеей для определенных классов. Пересмешивание упрощается с помощью интерфейсов, и когда вы используете контейнер IoC, тогда интерфейсы начинают иметь смысл, особенно когда вы начинаете внедрять службы, совместно используемые в этом контейнере. После этого вы сможете отделить реализацию службы от класса, нуждающегося в услуге.
Помимо причин, приведенных в других ответах, только реализация интерфейса позволяет перехватывать методы путем создания прокси-серверов без использования инструментария. Это используется для регистрации, инкапсуляции операций в транзакции и т. Д. Он используется несколькими платформами.
Я нахожу включение интерфейса, когда вы знаете, что он никогда не будет реализован ничем, кроме этого одного класса, просто раздражает. Как правило, мой редактор кода настроен так, что я нажимаю функциональную клавишу, чтобы перейти к определению функции. Когда интерфейс присутствует, я оказываюсь в определении интерфейса, а не в реализации. Затем я должен найти реальную реализацию. Количество времени, которое мне это стоило, с лихвой компенсировало время, потраченное на удаление и повторную реализацию этого интерфейса. Я время от времени удалял такой интерфейс, и мне никогда не приходилось заново реализовывать тот, который я решил удалить. С точки зрения модульного тестирования, современные фиктивные системы полностью устранили необходимость в этом интерфейсе.
Да, в интерфейсах есть смысл, так как в будущем может быть несколько реализаций. Вы, конечно, можете пойти за борт и создать интерфейсы для всего, так что здесь есть баланс.
Даже если люди не совсем согласны с количеством ошибок на 1000 строк кода, эти два кажутся коррелированными ( https://stackru.com/questions/862277/what-is-the-industry-standard-for-bugs-per-1000-lines-of-code). Меньше строк == меньше ошибок.
Кроме того, изменение имени реализации для имени интерфейса должно быть все, что нужно сделать здесь.
Если усилия по рефакторингу минимальны, и это уменьшает код, я буду скорее подавлять интерфейс.