Назви інтерфейсів на Java [закрито]


324

Більшість мов OO мають префікс своїх імен інтерфейсу з великої літери I, чому Java не робить цього? Що було обґрунтуванням недотримання цієї конвенції?

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

  1. Клас = Користувач, Інтерфейс = Інтерфейс користувача
  2. Клас = UserImpl, інтерфейс = користувач

Де на більшості мов:

Клас = Користувач, Інтерфейс = IUser

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

Отже, я думаю, моє запитання зводиться до: "Чи варто дотримуватися більш широкої конвенції про іменування інтерфейсів, особливо з огляду на те, куди, начебто, рухаються рамки Java Frameworks?"


61
"Де на більшості мов"? Які мови, окрім .Net?
вд

2
Різні мовні спільноти мають різні угоди про іменування, і це справедливо давно, довго. З’ясування того, як виникли конвенції про іменування, по суті є фольклорним дослідженням.
Девід Торнлі

4
Eclipse - це значне, що використовує Java з іменами стилю IFoo. wiki.eclipse.org/Naming_Conventions
Девід Леонард

2
Якщо ви подивіться на імена інтерфейсів в Android SDK (Java, а), ви побачите , що вони використовували конвенції мати слово інтерфейс на кінці імені інтерфейсу, наприклад NetworkInterface, DialogInterfaceі т.д.
sandalone

21
Як це питання можна "закрити як неконструктивне", коли воно настільки популярне і цікавить стільки людей?
inor

Відповіді:


329

Я вважаю за краще не використовувати префікс на інтерфейсах:

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

  • Використання інтерфейсів у клієнтів - це стандартний найкращий спосіб програмування, тому імена інтерфейсів повинні бути максимально короткими та приємними. Реалізація занять повинна бути більш неприємною, щоб відмовити від їх використання.

  • При переході від абстрактного класу до інтерфейсу конвенція кодування з префіксом I передбачає перейменування всіх випадків класу --- не добре!


12
Повністю згоден. Ще один ключ для введення, якщо ви використовуєте автоматичне завершення. Багато файлів, що починаються з I.
Kalecser

85
Будь-який гідний IDE спрощує зміну коду так, як ви описуєте. Також, переходячи від абстрактного класу до інтерфейсу, я впевнений, що вашим клієнтам все одно доведеться перекомпілювати.
Аллайн Лалонде

63
Супер пізно тут, але: не має значення взагалі , якщо IDE робить зміна імені чого - то легко. Код, що використовує екземпляр якогось типу, ніколи не повинен хвилювати, чи цей тип інтерфейсу чи класу чи що. Таким чином, викривати таку деталь у назві типу безглуздо і шкідливо для розуміння. Тип і договір, який він виставляє, є важливими!
ColinD

11
Крім того, якщо ви рухаєтесь по маршруту IFoo, якщо це не CFoo для впровадження, і, звичайно, у випадку відмови метод би кинув EFoo.
Робін

57
"Префікс шкодить читабельності" суто суб'єктивний. Як і більшість угод про іменування. Важливо, щоб ваша команда домовлялася про те, що робити, щоб база коду була узгодженою.
dreadwail

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

Я думаю, ви б хотіли знати його DAO, оскільки це описує загальну функціональність без необхідності відкривати клас. Якщо я переглядаю файли класу в проекті, його легко побачити всі DAO, шукаючи * DAO
Патрік

6
DAO - це добре відомий зразок доступу до бази даних, тому, маючи шаблон у імені, можна легко зрозуміти, що робить клас, просто переглянувши його ім'я. PS Було б краще суворо дотримуватися позначення верблюдів ("AccountDao"), таких як mina.apache.org/changes-between-2x-and-1x.html
Esko Luontola

4
@marker, це не так, як I, щоб вказати інтерфейс. DAO повідомляє вам, що клас або інтерфейс - це об'єкт для доступу до даних облікових записів, що і робить об’єкт. Маючи I, я розповідаю вам про його інтерфейс, який не має нічого спільного з самим об'єктом, крім семантикою мови
tddmonkey

Поки ви представляєте його префікс vs суфікс.
Андрій Ронеа

3
@Andrei: Ні, це семантика ("DAO") проти непотрібного декору мовного артефакту ("Я" як в інтерфейсі; факт, який у коді згадується в будь-якому випадку "інтерфейс IFoo ...")
Дірк

75

Причин може бути декілька, чому Java взагалі не використовує конвенцію IUser.

  1. Частина об'єктно-орієнтованого підходу полягає в тому, що вам не доведеться знати, чи використовує клієнт інтерфейс або клас реалізації. Отже, навіть List - це інтерфейс, а String - це фактичний клас, метод може бути переданий обом - не має сенсу візуально розрізняти інтерфейси.

  2. Взагалі ми будемо віддавати перевагу використанню інтерфейсів у коді клієнта (наприклад, надайте список списку ArrayList). Тому не має сенсу робити так, щоб інтерфейси виділялися виключеннями.

  3. Конвенція про іменування Java надає перевагу довшим іменам із фактичними значеннями префіксам угорського стилю. Отже, цей код буде максимально читабельним: список представляє список, а користувач представляє користувача, а не IUser.


72

Існує також інша конвенція, яка використовується багатьма проектами з відкритим кодом, включаючи Весну.

interface User {
}

class DefaultUser implements User {
}

class AnotherClassOfUser implements User {
}

Мені особисто не подобається префікс "Я" з тієї простої причини, що його необов'язкова умова. Отже, якщо я прийму це, чи означає IIOPConnection інтерфейс для IOPConnection? Що робити, якщо у класу немає префікса "Я", чи знаю я його не інтерфейс? Відповідь тут "ні", тому що конвенції не завжди дотримуються, а поліцейський контроль за ними створить більше роботи, яку збереже сама конвенція.


Мені це подобається, оскільки це також допомагає перейти в режим використання інтерфейсів для зовнішніх залежностей, а не з'єднання класів.
Метт Бріггс

47

Як сказав інший плакат, зазвичай краще, щоб інтерфейси визначали можливості, а не типи. Я б схильний не "реалізовувати" щось на кшталт "Користувача", і саме тому "IUser" часто не дуже потрібний описаним тут способом. Я часто бачу класи як іменники та інтерфейси як прикметники:

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

Іноді прикметник не має сенсу, але я все-таки використовую інтерфейси для моделювання поведінки, дій, можливостей, властивостей тощо, а не типів.

Крім того, якщо ви дійсно збиралися зробити одного Користувача і назвати його Користувачем, то який сенс також мати інтерфейс IUser? І якщо у вас буде кілька користувачів різних типів, яким потрібно реалізувати загальний інтерфейс, що додавання "Я" до інтерфейсу заощадить у виборі імен реалізацій?

Я думаю, що більш реалістичним прикладом може бути те, що деякі типи користувачів повинні мати можливість увійти до певного API. Ми могли б визначити інтерфейс для входу, а потім мати батьківський клас "Користувач" із суперкласами SuperUser, DefaultUser, AdminUser, AdministrativeContact та ін., Деякі з яких будуть чи не реалізуватимуть інтерфейс Login (Logible?) За необхідності.


Я думаю, що приклади, які ви надаєте для підтримки "інтерфейсів як прикметників", перекошені, оскільки ці інтерфейси призначені більше схожі на змішування (або риси). Таким чином, інтерфейси хороші як для прикметників, так і для іменників, але, ймовірно, не для indefinite transitive verbs 8 ^ P
Stevel

Це може змінитися за останні роки. Документ оракула. дозволяє інтерфейси як типи: [посилання] docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
karlihnos

38

Боб Лі сказав один раз на презентації:

у чому сенс інтерфейсу, якщо у вас є лише одна реалізація.

Отже, ви починаєте з однієї реалізації, тобто без інтерфейсу. пізніше ви вирішите, ну тут потрібен інтерфейс, тому ви перетворите свій клас в інтерфейс.

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

тож стає зрозуміло -> Інтерфейс Реалізація користувача UserImpl.


18
Використання інтерфейсів допоможе перевірити розробку. Ми зіткнулися з численними проблемами з доменною моделлю та тестуванням, оскільки вирішили НЕ використовувати інтерфейси. Один мій друг колись цитував: "Все - це інтерфейс, це врятує вас у довгостроковій перспективі".
підключення

4
Знущальна та проста підтримка проксі. Я впевнений, що є й інші причини для надання інтерфейсів.
MetroidFan2002

3
Як я нещодавно сказав колезі, впроваджувати інтерфейс зараз нічого не коштує, але згодом ви зможете заощадити багато часу.
tddmonkey

2
Якщо у вас можуть бути інші реалізації в найближчому середньому майбутньому, інтерфейс буде плюсом.
Стеф

3
Мені не подобається аргумент "мені може знадобитися інший імпульс у майбутньому". Я вважаю за краще підхід 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 .


Якщо єдиним користувачем, якого ви коли-небудь маєте намір, є Користувач, чому б не просто використовувати User замість інтерфейсу?
Каріган

3
У деяких архітектурах клієнт / сервер клієнтові необхідно знати інтерфейси, не потребуючи важких реалізацій сервера.
Девід Коелл

5

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

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

ніж це:

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

Якщо ви дотримуєтесь цієї ідеї, то я стверджую, що ваш код буде більш читабельним, якщо ви дасте імена інтерфейсів, наприклад "User" та "BankAccount" (наприклад), а не "IUser", "UserInterface" або інші варіанти.

Єдині біти коду, які повинні піклуватися про фактичні конкретні класи - це місця, де будуються конкретні класи. Все інше слід писати за допомогою інтерфейсів.

Якщо ви це зробите, то "потворні" конкретні назви класів на кшталт "UserImpl" повинні бути безпечно приховані від решти коду, який може весело продовжувати використання "nice" імен інтерфейсу.


Але навіщо турбуватися робити відповідний інтерфейс для кожного класу вашої програми, коли вам потрібні інтерфейси лише для однієї чи двох речей?
LegendLength

3

= v = Префікс "Я" також використовується в рамках Wicket, де я швидко звик до нього. Загалом, я вітаю будь-яку умову, яка скорочує громіздкі назви класів Java. Хоча, все, що в каталогах та в Javadoc все позначається за "Я".

Практика кодування Wicket схожа на Swing, оскільки багато екземплярів управління / віджетів будуються як анонімні внутрішні класи з вбудованими деклараціями методу. Прикро, що він відрізняється на 180 ° від Swing тим, що Swing використовує префікс ("J") для класів реалізації.

Суфікс "Impl" - це манірне абревіатура і не інтернаціоналізується добре. Якби ми хоча б пішли з "Imp", це було б симпатичніше (і коротше). "Impl" використовується для МОК, особливо Spring, тому ми зараз начебто застрягли з ним. Однак, це отримує трохи шизо після 3 різних конвенцій у трьох різних частинах однієї бази коду.


0

Це більш широка конвенція про іменування в будь-якому реальному сенсі? Я більше на стороні C ++, а не дуже на Яві та нащадках. Скільки мовних спільнот використовують I конвенцію?

Якщо у вас є стандартна умова іменування магазину, незалежна від мови, використовуйте її. Якщо ні, перейдіть за умовами назви мови.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.