Соглашение об именах интерфейсов Java/Реализация

Как вы называете разные классы/интерфейсы, которые вы создаете? Иногда у меня нет информации о реализации, чтобы добавить к имени реализации - как интерфейс FileHandler и class SqlFileHandler.

Когда это происходит, я обычно называю интерфейс "нормальным" именем, например Truck, и называю фактический класс TruckClass.

Как вы называете интерфейсы и классы в этом отношении?

Ответ 1

Назовите свой Interface, что это такое. Truck. Не ITruck, потому что это не ITruck, это Truck.

An Interface в Java - это Type. Тогда у вас есть DumpTruck, TransferTruck, WreckerTruck, CementTruck и т.д., Что implement Truck.

Когда вы используете Interface вместо подкласса, вы просто набрасываете его на Truck. Как и в List<Truck>. Помещение I впереди - это просто дрянное венгерское обозначение стиля tautology, которое добавляет ничего, кроме всего, что нужно набрать для вашего кода.

Все современные Java IDE маркируют интерфейсы и реализации и что не без этой глупой нотации. Не называйте это TruckClass tautology так же плохо, как тавтология IInterface.

Если это реализация, это класс. Единственным реальным исключением из этого правила и всегда есть исключения, является AbstractTruck. Поскольку только подклассы когда-либо видят это, и вы никогда не должны бросать класс Abstract, он добавляет некоторую информацию о том, что класс является абстрактным и как его следует использовать. Вы могли бы придумать лучшее имя, чем AbstractTruck, и вместо этого использовать BaseTruck. Но так как классы Abstract никогда не должны быть частью какого-либо открытого интерфейса, это приемлемое исключение из правила. Создание конструкторов protected имеет большое значение для пересечения этого деления.

И суффикс Impl - это еще больше шума. Больше тавтологии. Все, что не является интерфейсом, представляет собой реализацию, даже абстрактные классы, которые являются частичными реализациями. Собираетесь ли вы наложить этот глупый суффикс Impl на каждое имя каждого Class?

Interface - это контракт на то, что должны поддерживать общественные методы и свойства, а также Type. Все, что реализует Truck, это Type Truck.

Посмотрите на стандартную библиотеку Java. Вы видите IList, ArrayListImpl, LinkedListImpl? Нет, вы видите List и ArrayList, и LinkedList. Вот хорошая статья об этом точном вопросе. Любые из этих глупых соглашений о присвоении имен префиксов/суффиксов все нарушают принцип DRY.

Кроме того, если вы добавляете DTO, JDO, BEAN или другие глупые повторяющиеся суффиксы к объектам, то они, вероятно, принадлежат package вместо всех этих суффиксов. Правильно упакованные пространства имен являются собственными документами и уменьшают всю бесполезную избыточную информацию в этих действительно плохо продуманных проприетарных схемах именования, которые большинство мест даже не придерживаются единообразно.

Если вы можете придумать, чтобы ваше имя Class было уникальным, оно суффиктировало его с помощью Impl, тогда вам нужно переосмыслить наличие Interface вообще. Итак, когда у вас есть ситуация, когда у вас есть Interface и один Implementation, который не уникально специализирован из Interface, вам, вероятно, не нужен Interface.

Ответ 2

Я видел ответы здесь, которые предполагают, что если у вас есть только одна реализация, вам не нужен интерфейс. Это летит перед лицом принципа "Инжекция/инверсия принципа подчинения" (не звоните нам, мы позвоним вам!).

Итак, есть ситуации, когда вы хотите упростить свой код и сделать его легко проверяемым, полагаясь на внедренные реализации интерфейса (которые также могут быть проксированы - ваш код не знает!). Даже если у вас есть только две реализации: одна - Mock для тестирования, и одна, которая вводится в фактический производственный код, - это не делает излишним интерфейс. Хорошо документированный интерфейс устанавливает контракт, который также может поддерживаться строгой реализацией для тестирования.

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

Инъекция зависимостей /IOC может быть трудно понять для новичков, но как только вы поймете ее потенциал, вы захотите использовать ее повсюду, и вы будете постоянно создавать интерфейсы - даже если будет только быть одним (фактическим производством).

Для этой одной реализации (вы можете сделать вывод, и вы будете правы, что я считаю, что макеты для тестирования должны называться Mock (InterfaceName)), я предпочитаю имя Default (InterfaceName). Если произойдет более конкретная реализация, ее можно назвать соответствующим образом. Это также исключает суффикс Impl, который мне особенно не нравится (если это не абстрактный класс, OF COURSE это "impl"!).

Я также предпочитаю "Base (InterfaceName)" в отличие от "Abstract (InterfaceName)", потому что есть некоторые ситуации, в которых вы хотите, чтобы ваш базовый класс стал доступен позже, но теперь вы застряли с именем "Abstract ( InterfaceName)", и это заставляет вас переименовать класс, возможно, вызвав небольшую путаницу, но если бы он всегда был Base (InterfaceName), удаление абстрактного модификатора не меняло бы класс.

Ответ 3

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

Если существует только один класс реализации, и вы не можете думать ни о чем, что делает его конкретным (подразумевается, желая назвать его -Impl), то похоже, что нет никакого оправдания для интерфейса вообще.

Ответ 4

Я склонен следовать псевдо-соглашениям, установленным Java Core/Sun, например. в классах Коллекции:

  • List - интерфейс для "концептуального" объекта
  • ArrayList - конкретная реализация интерфейса
  • LinkedList - конкретная реализация интерфейса
  • AbstractList - абстрактная "частичная" реализация для поддержки пользовательских реализаций

Я использовал то же самое, что и моделирование классов событий после парадигмы AWT Event/Listener/Adapter.

Ответ 5

Стандартное соглашение С#, которое хорошо работает и в Java, - это префикс всех интерфейсов с I, поэтому ваш интерфейс обработчика файлов будет IFileHandler, а ваш интерфейс вашего грузовика будет ITruck. Это непротиворечиво и позволяет легко рассказать интерфейсы из классов.

Ответ 6

Мне нравятся имена интерфейсов, которые указывают, какой контракт описывает интерфейс, например "Comparable" или "Serializable". Существительные типа "Грузовик" на самом деле не описывают грузовик - каковы Способности грузовика?

Относительно соглашений: я работал над проектами, где каждый интерфейс начинается с "I"; в то время как это несколько чуждо к соглашениям Java, это делает поиск интерфейсов очень легким. Кроме того, суффикс "Impl" является разумным именем по умолчанию.

Ответ 7

Некоторым людям это не нравится, и это скорее соглашение .NET, чем Java, но вы можете назвать свои интерфейсы префиксом капитала I, например:

IProductRepository - interface
ProductRepository, SqlProductRepository, etc. - implementations

Люди, выступающие против этого соглашения об именах, могут утверждать, что вам все равно, работаете ли вы с интерфейсом или объектом в коде, но мне легче читать и понимать на лету.

Я бы не назвал класс реализации суффиксом класса. Это может привести к путанице, поскольку вы действительно можете работать с объектами класса (т.е. типа) в своем коде, но в вашем случае вы не работаете с объектом класса, вы просто работаете с простым старым объектом.

Ответ 8

TruckClass звучит как класс Truck, я думаю, что рекомендуемое решение - добавить суффикс Impl. На мой взгляд, лучшим решением является включение внутри имени реализации некоторой информации, что происходит в этой конкретной реализации (например, у нас есть с интерфейсом List и реализациями: ArrayList или LinkedList), но иногда у вас есть только одна реализация и должен иметь интерфейс из-за удаленного использования (например), то (как упоминалось в начале) Impl является решением.

Ответ 9

Я использую оба соглашения:

Если интерфейс является конкретным экземпляром хорошо известного шаблона (например, Service, DAO), тогда ему может не понадобиться "I" (например, UserService, AuditService, UserDao), все работают нормально без "I", поскольку post-fix определяет мета-шаблон.

Но если у вас есть что-то одноразовое или двухкратное (обычно для шаблона обратного вызова), то это помогает отличить его от класса (например, IAsynchCallbackHandler, IUpdateListener, IComputeDrone). Это интерфейсы специального назначения, предназначенные для внутреннего использования, иногда IInterface обращает внимание на то, что операнд на самом деле является интерфейсом, поэтому на первый взгляд сразу становится ясно.

В других случаях вы можете использовать I, чтобы избежать столкновения с другими общеизвестными конкретными классами (ISubject, IPrincipal vs Subject или Principal).