Именование интерфейса в Java [закрыто]

324

Большинство языков OO ставят перед именами интерфейсов заглавные буквы I, почему Java этого не делает? Что послужило основанием для несоблюдения этого соглашения?

Чтобы продемонстрировать, что я имею в виду, если бы я хотел иметь пользовательский интерфейс и пользовательскую реализацию, у меня было бы два варианта в Java:

  1. Класс = Пользователь, Интерфейс = Пользовательский Интерфейс
  2. Класс = UserImpl, Интерфейс = Пользователь

Где на большинстве языков:

Класс = Пользователь, Интерфейс = IUser

Теперь вы можете утверждать, что вы всегда можете выбрать наиболее описательное имя для пользовательской реализации, и проблема исчезнет, ​​но Java продвигает подход POJO к вещам, и большинство контейнеров IOC широко используют DynamicProxies. Эти две вещи вместе означают, что у вас будет много интерфейсов с одной реализацией POJO.

Итак, я предполагаю, что мой вопрос сводится к следующему: «Стоит ли следовать более широкому соглашению об именах интерфейсов, особенно в свете того, куда движется Java Frameworks?»

Аллен Лалонд
источник
61
"Где в большинстве языков"? Какие языки кроме .Net?
wds
2
Различные языковые сообщества имеют разные соглашения об именах, и это было верно в течение долгого времени. Выяснение того, как возникли соглашения об именах, иногда является по сути фольклорным исследованием.
Дэвид Торнли
4
Eclipse - значительный выброс, использующий Java с именами в стиле IFoo. wiki.eclipse.org/Naming_Conventions
Дэвид Леонард
2
Если вы посмотрите на имена интерфейсов в Android SDK (в том числе и на Java), вы увидите, что они использовали соглашение о наличии слова Interface в конце имени интерфейса, например NetworkInterface, DialogInterfaceи т. Д.
sandalone
21
Как этот вопрос может быть «закрыт как неконструктивный», когда он настолько популярен и интересен для многих людей?
INOR

Ответы:

329

Я предпочитаю не использовать префикс на интерфейсах:

  • Префикс ухудшает читабельность.

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

  • При переходе от абстрактного класса к интерфейсу соглашение о кодировании с префиксом I подразумевает переименование всех вхождений класса - не хорошо!

starblue
источник
12
Полностью согласен. Еще один ключ для ввода, если вы используете автозаполнение. Много файлов, начинающихся с I.
Kalecser
85
Любая приличная IDE позволяет легко изменить код так, как вы его описываете. Кроме того, при переходе от абстрактного класса к интерфейсу я почти уверен, что вашим клиентам все равно придется перекомпилировать.
Аллен Лалонд
63
Супер поздно здесь, но: не имеет значения вообще , если IDE делает изменение имени чего - то легко. Код, использующий экземпляр какого-либо типа, никогда не должен заботиться о том, является ли этот тип интерфейсом или классом или чем-то еще. Таким образом, разоблачение такой детали в названии типа бессмысленно и вредно для понимания. Тип и контракт, который он выставляет, имеют значение!
ColinD
11
Кроме того, если вы идете по пути IFoo, разве это не должен быть CFoo для реализации и, конечно же, в случае сбоя метод выдаст EFoo.
Робин
57
«Приставка ухудшает читабельность» - это чисто субъективно. Как и большинство соглашений об именах. Важно, чтобы ваша команда договорилась о том, что делать, чтобы база кода была согласованной.
ужасный ужас
121

Есть ли разница между:

class User implements IUser

и

class UserImpl implements User

если все, о чем мы говорим, это соглашения об именах?

Лично я предпочитаю НЕ предшествовать интерфейсу, Iпоскольку хочу кодировать интерфейс, и считаю, что это более важно с точки зрения соглашения об именах. Если вы вызываете интерфейс, IUserто каждый потребитель этого класса должен знать его IUser. Если вы вызываете класс, UserImplто только часть и ваш DI-контейнер знают о Implдетали, а потребители просто знают, что они работают с a User.

С другой стороны, времена, которые я был вынужден использовать, Implпотому что лучшее имя не представляет себя, были немногочисленны, потому что реализация получает имя в соответствии с реализацией, потому что именно там это важно, например

class DbBasedAccountDAO implements AccountDAO
class InMemoryAccountDAO implements AccountDAO
tddmonkey
источник
Я думаю, что вы хотели бы знать, что это DAO, так как он описывает общую функциональность без необходимости открывать класс. Если я просматриваю файлы классов в проекте, то легко увидеть все DAO, выполнив поиск * DAO
Patrick
6
DAO - это хорошо известный шаблон для доступа к базе данных, поэтому наличие шаблона в имени позволяет легко узнать, что делает класс, просто взглянув на его имя. PS Было бы лучше строго следовать обозначениям верблюда («AccountDao»), например, в mina.apache.org/changes-between-2x-and-1x.html
Esko Luontola
4
@marker, это не то же самое, что иметь I для обозначения интерфейса. DAO сообщает вам, что класс или интерфейс - это объект для доступа к данным учетной записи, что и делает объект. Имея I, я говорю вам, что это интерфейс, который не имеет ничего общего с самим объектом, но семантикой языка
tddmonkey
Как вы представляете, его префикс против суффикса.
Андрей Ринея
3
@Andrei: Нет, это семантика («DAO») и ненужное оформление языкового артефакта («I» как в интерфейсе; факт, который упоминается в коде в любом случае «интерфейс IFoo ...»)
Дирк
75

Может быть несколько причин, по которым Java обычно не использует соглашение IUser.

  1. Частью объектно-ориентированного подхода является то, что вам не нужно знать, использует ли клиент интерфейс или класс реализации. Таким образом, даже List - это интерфейс, а String - реальный класс, метод может быть передан им обоим - визуально различать интерфейсы не имеет смысла.

  2. В общем, мы на самом деле предпочтем использовать интерфейсы в клиентском коде (например, предпочтение от List ArrayList). Поэтому не имеет смысла выделять интерфейсы как исключения.

  3. Соглашение об именах Java предпочитает более длинные имена с фактическим значением префиксам в венгерском стиле. Таким образом, этот код будет максимально читабельным: список представляет список, а пользователь представляет пользователя, а не IUser.

Avi
источник
72

Существует также другое соглашение, используемое многими проектами с открытым исходным кодом, включая Spring.

interface User {
}

class DefaultUser implements User {
}

class AnotherClassOfUser implements User {
}

Мне лично не нравится префикс «я» по той простой причине, что это необязательное соглашение. Таким образом, если я принимаю это, означает ли IIOPConnection интерфейс для IOPConnection? Что, если у класса нет префикса «I», тогда я знаю, что он не является интерфейсом… ответ здесь - нет, потому что соглашения не всегда соблюдаются, и их применение будет создавать больше работы, которую сохраняет само соглашение.

нг.
источник
Мне это нравится, так как это также помогает вам перейти в режим использования интерфейсов для внешних зависимостей, а не связывания классов.
Мэтт Бриггс
47

Как сказал другой автор, обычно предпочтительнее, чтобы интерфейсы определяли возможности, а не типы. Я бы не стал «реализовывать» что-то вроде «пользователя», и именно поэтому «IUser» часто не является действительно необходимым способом, описанным здесь. Я часто вижу классы как существительные и интерфейсы как прилагательные:

class Number implements Comparable{...}  
class MyThread implements Runnable{...}
class SessionData implements Serializable{....}

Иногда прилагательное не имеет смысла, но я все же обычно использую интерфейсы для моделирования поведения, действий, возможностей, свойств и т. Д., А не типов.

Кроме того, если вы действительно собирались сделать только одного пользователя и назвать его пользователем, то какой смысл также иметь интерфейс IUser? И если у вас будет несколько разных типов пользователей, которым необходимо реализовать общий интерфейс, что, добавив «I» к интерфейсу, спасет вас при выборе имен реализаций?

Я думаю, что более реалистичным примером будет то, что некоторые типы пользователей должны иметь возможность входить в конкретный API. Мы могли бы определить интерфейс входа в систему, а затем иметь родительский класс «Пользователь» с классами SuperUser, DefaultUser, AdminUser, AdministrativeContact и т. Д., Некоторые из которых будут или не будут реализовывать интерфейс Login (Loginable?) По мере необходимости.

nairbv
источник
Я думаю, что примеры, которые вы предоставляете для поддержки «интерфейсов как прилагательных», искажены, так как эти интерфейсы предназначены для того, чтобы больше походить на встраивания (или черты). Таким образом, интерфейсы хороши как для прилагательных, так и для существительных, но, вероятно, не для indefinite transitive verbs 8 ^ P
Stevel
Это может быть изменено в последние годы. Документ оракула. разрешает интерфейсы как типы: [ссылка] docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
karlihnos
38

Боб Ли сказал однажды в презентации:

какой смысл интерфейса, если у вас есть только одна реализация.

Итак, вы начинаете с одной реализации, т.е. без интерфейса. позже вы решите, ну, здесь нужен интерфейс, поэтому вы конвертируете свой класс в интерфейс.

тогда становится очевидно: ваш исходный класс назывался User. Ваш интерфейс теперь называется User. может быть, у вас есть UserProdImpl и UserTestImpl. если вы хорошо спроектировали свое приложение, все классы (кроме тех, которые создают экземпляр User) останутся неизменными и не заметят, что вдруг они получат интерфейс.

так становится понятно -> Интерфейс пользователя, реализация UserImpl.

Андреас Петерссон
источник
18
Использование интерфейсов поможет протестировать управляемую разработку. Мы столкнулись с многочисленными проблемами, связанными с моделью домена и тестированием, потому что решили НЕ использовать интерфейсы. Мой друг однажды процитировал: «Все это интерфейс, он спасет вас в долгосрочной перспективе».
hooknc
4
Насмешливая и простая поддержка прокси. Я уверен, что есть и другие причины для предоставления интерфейсов.
MetroidFan2002,
3
Как я недавно сказал коллеге, внедрение интерфейса сейчас ничего не стоит, но может сэкономить вам много времени в дальнейшем.
tddmonkey
2
Если у вас могут быть другие реализации в ближайшем будущем, интерфейс будет плюсом.
Стеф
3
Мне не нравится аргумент "мне может понадобиться еще один impl в будущем". Я предпочитаю подход YAGNI: не планируйте того, что еще не произошло.
Дэвид Лавендер,
24

В C # это

public class AdminForumUser : UserBase, IUser

Ява сказала бы

public class AdminForumUser extends User implements ForumUserInterface

Из-за этого я не думаю, что соглашения в Java так же важны для интерфейсов, поскольку существует явная разница между наследованием и реализацией интерфейса. Я бы сказал, просто выберите любое соглашение об именах, которое вы хотите, если вы последовательны и использовать что-то, чтобы показать людям, что это интерфейсы. Я не делал java в течение нескольких лет, но все интерфейсы были бы в их собственном каталоге, и это было условием. Никогда не было проблем с этим.

Мэтт Бриггс
источник
22
Может быть, я плохой Java-кодер, но я предпочитаю стиль C #, означает, что все интерфейсы начинаются с префикса 'I' :)
davs
7
Я не уверен, откуда вы и другие получаете эту предполагаемую конвенцию. Это не очевидно в библиотеках Java ...
ChiefTwoPencils
6

По моему опыту, соглашение «Я» применяется к интерфейсам, которые предназначены для предоставления контракта классу, особенно когда сам интерфейс не является абстрактным понятием класса.

Например, в вашем случае я бы только ожидал увидеть, будет IUserли единственный пользователь, которого вы когда-либо намереваетесь иметь User. Если вы планируете иметь различные типы пользователей - NoviceUser, ExpertUserи т.д. - я бы ожидал увидеть Userинтерфейс (и, возможно, в AbstractUserкласс , который реализует некоторые общие функциональные возможности , как get/setName()).

Я хотел бы также ожидать , интерфейсы , которые определяют возможности - Comparable, Iterableи т.д. - должны быть названы так, и не так, как IComparableили IIterable.

Дэвид Коэль
источник
Если единственный пользователь, которого вы когда-либо намереваетесь иметь, это Пользователь, то почему бы просто не использовать Пользователя вместо интерфейса?
Кариган
3
В некоторых клиент-серверных архитектурах клиентская сторона должна знать интерфейсы, не нуждаясь в мощных реализациях сервера.
Дэвид
5

Следуя хорошим принципам ОО, ваш код должен (насколько это возможно / практично) зависеть от абстракций, а не от конкретных классов. Например, обычно лучше написать такой метод:

public void doSomething(Collection someStuff) {
    ...
}

чем это:

public void doSomething(Vector someStuff) {
    ...
}

Если вы следуете этой идее, то я утверждаю, что ваш код будет более читабельным, если вы дадите имена интерфейсов, такие как «Пользователь» и «BankAccount» (например), а не «IUser», «UserInterface» или другие варианты.

Единственные фрагменты кода, которые должны заботиться о реальных конкретных классах, - это места, где создаются конкретные классы. Все остальное должно быть написано с использованием интерфейсов.

Если вы сделаете это, то «уродливые» конкретные имена классов, такие как «UserImpl», должны быть безопасно скрыты от остальной части кода, который может весело продолжаться с использованием «хороших» имен интерфейсов.

KarstenF
источник
Но зачем создавать соответствующий интерфейс для каждого класса в вашей программе, когда вам нужны интерфейсы только для одной или двух вещей?
LegendLength
3

= v = Префикс «I» также используется в платформе Wicket, где я быстро к этому привык. В общем, я приветствую любые соглашения, которые сокращают громоздкие имена классов Java. Однако хлопотно, что все расположено в алфавитном порядке под «Я» в каталогах и в Javadoc.

Практика кодирования калитки похожа на Swing в том, что многие экземпляры элементов управления / виджетов создаются как анонимные внутренние классы с объявлениями встроенных методов. Досадно, что он отличается на 180 ° от Swing тем, что Swing использует префикс («J») для реализующих классов.

Суффикс "Impl" - мужественная аббревиатура, которая плохо интернационализируется. Если бы только мы по крайней мере пошли с "Imp", это было бы симпатичнее (и короче). «Impl» используется для МОК, особенно для Spring, так что мы пока застряли с ним. Впрочем, после трех разных соглашений в трех разных частях одной кодовой базы это становится немного шизо.

Джим Дайер
источник
0

Является ли это в более широком смысле соглашением об именах? Я больше на стороне C ++, и не очень разбираюсь в Java и потомках. Сколько языковых сообществ используют I конвенцию?

Если у вас есть соглашение о наименовании магазина, не зависящее от языка, используйте его. Если нет, воспользуйтесь соглашением об именах языков.

Дэвид Торнли
источник