#java
#java
Вопрос:
Я создаю макет класса для Lexer
объекта, и я думаю, что мне может понадобиться провести некоторый рефакторинг. У меня есть два варианта:
- Создайте интерфейс
Lexer
и переименуйте текущийLexer
во что-то вродеRealLexer
. ЕстьMockLexer
реализацияLexer
, и вызовы методов принимают любой типLexer
. Мне не нравится, что мой драгоценныйLexer
класс теперь переименован во что-то, что не имеет смысла, если вы не знаете, что есть макет класса. - Создайте интерфейс
LexerInterface
(который мне уже не нравится, поскольку он естьInterface
в его названии), но позволяя себе сохранить текущийLexer
таким, какой он есть.MockLexer
затем реализуетLexerInterface
. Другим недостатком является то, что вызовы методов принимаютсяLexerInterface
как параметры.
Оба варианта плохо пахнут для меня, поэтому я решил, что позволю стандартам решать за меня. У кого-нибудь был опыт работы с этим?
Комментарии:
1. Почему
RealLexer
? Просто назовите своеMockLexer
имя так, как вы хотите, поскольку оно будет использоваться только для тестирования. Тогда, можетLexer
быть, интерфейс иDefaultLexer
для реализации по умолчанию2. Ну, мне нравится MockLexer, поскольку он сразу сообщает сопровождающему, что его можно использовать только для макетных тестов. Но мне нравится «По умолчанию», а не «Реальный».
3. Правда, хорошей практикой является добавление макетных объектов
Mock
.
Ответ №1:
Я бы определенно проголосовал за использование Lexer
в качестве имени вашего интерфейса. Как насчет добавления некоторой информации о том, как или почему ваша реализация выполняет свою работу как часть имени? Например.:
StringParsingLexer
TokenizingLexer
SingleThreadedLexer
{ThirdPartyLibraryName}DelegatingLexer
Кроме того, вам действительно нужно явно создавать a MockLexer
? Использование фреймворка, такого как Mockito, может значительно упростить и ускорить ваше тестирование; Вы можете начать так же легко, как:
Lexer mockLexer = Mockito.mock(Lexer.class);
Mockito.when(mockLexer.doFoo()).thenReturn("bar");
Ответ №2:
Моя рекомендация, как я уже говорил в комментариях, заключается в использовании Lexer
для вашего интерфейса и DefaultLexer
для реализации по умолчанию. Этот шаблон используется довольно часто и как таковой очень понятен любому, кто будет поддерживать ваш код. Что касается макетного объекта, также было бы понятно назвать это как-то так MockLexer
.
В качестве примера соглашения об именовании, используемого Java:
javax.swing.table.TableModel
является ли интерфейс
javax.swing.table.AbstractTableModel
является ли реализация абстрактного класса реализацией TableModel
javax.swing.table.DefaultTableModel
AbstractTableModel
.
Однако в соглашениях о кодировании Java нет рекомендаций, кроме использования заглавных букв, существительных и т. Д.
Ответ №3:
Я обычно использую вариант 1 — вызываемые интерфейсы Lexer
, при этом реализации по умолчанию называются либо DefaultLexer
или LexerImpl
. Мне это нравится, потому что я думаю, что это позволяет вам легко говорить о классах — если у вас есть несколько реализаций Lexer
s, то их конкретные имена могут описывать тип реализации — например NativeLexer
, или TreeBasedLexer
или что угодно. Как упоминал комментатор, тогда ваш макет класса (если он у вас есть) может следовать этому шаблону с именем, подобным MockLexer
.
Однако с помощью библиотек-макетов, таких как excellent Mockito, вы все равно можете имитировать конкретные классы, поэтому вам больше не нужно использовать интерфейсы везде, чтобы легко тестировать вещи. Вот пример, который они приводят в своей документации:
//You can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
Тем не менее, я бы все же рекомендовал использовать интерфейсы вместо привязки сигнатур методов к конкретным классам, потому что тогда используемые вещи Lexer
не нужно привязывать к реализации — это может значительно повысить удобство обслуживания (например, если вам потребуется несколько реализаций позже).
Ответ №4:
По моему опыту, существует два стандарта.
- «Пометьте» свой интерфейс. (
ILexer
,LexerInterface
, и т.д.) - Используйте имя для вашего интерфейса и используйте другое имя для конкретной реализации.
Я знаю, что это уже представленные вами варианты. Проблема в том, что ни один из них не является «стандартом».
Я настоятельно предпочитаю вариант 2). Имя класса для объекта должно иметь тенденцию быть существительным, которое вписывается в контекст предложения «is-a». Странно говорить, что объект «is-a» LexerInterface
, тогда как естественно сказать, что объект «is-a» DefaultLexer
.
Поскольку в конечном итоге имя моего класса или интерфейса представляет тип, я уклоняюсь от «мета» информации в имени класса или интерфейса.