Соглашение об именовании интерфейса / класса / макета класса в Java?

#java

#java

Вопрос:

Я создаю макет класса для Lexer объекта, и я думаю, что мне может понадобиться провести некоторый рефакторинг. У меня есть два варианта:

  1. Создайте интерфейс Lexer и переименуйте текущий Lexer во что-то вроде RealLexer . Есть MockLexer реализация Lexer , и вызовы методов принимают любой тип Lexer . Мне не нравится, что мой драгоценный Lexer класс теперь переименован во что-то, что не имеет смысла, если вы не знаете, что есть макет класса.
  2. Создайте интерфейс 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:

По моему опыту, существует два стандарта.

  1. «Пометьте» свой интерфейс. ( ILexer , LexerInterface , и т.д.)
  2. Используйте имя для вашего интерфейса и используйте другое имя для конкретной реализации.

Я знаю, что это уже представленные вами варианты. Проблема в том, что ни один из них не является «стандартом».

Я настоятельно предпочитаю вариант 2). Имя класса для объекта должно иметь тенденцию быть существительным, которое вписывается в контекст предложения «is-a». Странно говорить, что объект «is-a» LexerInterface , тогда как естественно сказать, что объект «is-a» DefaultLexer .

Поскольку в конечном итоге имя моего класса или интерфейса представляет тип, я уклоняюсь от «мета» информации в имени класса или интерфейса.