Nazwy interfejsów w Javie [zamknięte]

324

Większość języków OO poprzedza swoje nazwy interfejsów wielką literą I, dlaczego Java tego nie robi? Jakie było uzasadnienie nieprzestrzegania tej konwencji?

Aby zademonstrować, co mam na myśli, gdybym chciał mieć interfejs użytkownika i implementację użytkownika, miałbym dwie możliwości w Javie:

  1. Klasa = Użytkownik, Interfejs = Interfejs użytkownika
  2. Klasa = UserImpl, Interfejs = Użytkownik

Gdzie w większości języków:

Klasa = Użytkownik, Interfejs = Użytkownik

Teraz możesz argumentować, że zawsze możesz wybrać najbardziej opisową nazwę dla implementacji użytkownika, a problem zniknie, ale Java popycha podejście POJO do rzeczy, a większość kontenerów IOC intensywnie korzysta z DynamicProxies. Te dwie rzeczy razem oznaczają, że będziesz mieć wiele interfejsów z jedną implementacją POJO.

Wydaje mi się, że moje pytanie sprowadza się do: „Czy warto stosować szerszą konwencję nazewnictwa interfejsów, zwłaszcza w świetle tego, dokąd zmierzają frameworki Java?”

Allain Lalonde
źródło
61
„Gdzie w większości języków”? Które języki oprócz .Net?
wds
2
Różne społeczności językowe mają różne konwencje nazewnictwa, i to było prawdą przez długi, długi czas. Dowiedzenie się, jak powstały konwencje nazewnictwa, jest czasem głównie badaniami folklorystycznymi.
David Thornley,
4
Eclipse to znacząca wartość odstająca, która korzysta z języka Java z nazwami w stylu IFoo. wiki.eclipse.org/Naming_Conventions
David Leonard
2
Jeśli spojrzeć na nazwy interfejsów w Android SDK (Java, jak również), widać, że stosowane są Konwencji posiadające interfejs słowo na końcu nazwy interfejsu, jak NetworkInterface, DialogInterfaceitp
sandalone
21
Jak to pytanie można „zamknąć jako mało konstruktywne”, skoro jest tak popularne i interesujące dla tak wielu osób?
inor

Odpowiedzi:

329

Wolę nie używać prefiksu na interfejsach:

  • Prefiks szkodzi czytelności.

  • Używanie interfejsów w klientach jest standardowym najlepszym sposobem programowania, dlatego nazwy interfejsów powinny być możliwie krótkie i przyjemne. Wdrażanie klas powinno być brzydsze, aby zniechęcić do ich używania.

  • Przy zmianie klasy abstrakcyjnej na interfejs konwencja kodowania z prefiksem I implikuje zmianę nazwy wszystkich wystąpień klasy --- niedobrze!

starblue
źródło
12
Kompletnie się zgadzam. Jeszcze jeden klucz do wpisania, jeśli używasz autouzupełniania. Wiele plików zaczynających się na I.
Kalecser
85
Każde przyzwoite IDE sprawia, że ​​zmiana kodu w sposób, który opisujesz, jest łatwa. Ponadto, kiedy zmieniam klasę abstrakcyjną na interfejs, jestem pewien, że Twoi klienci i tak będą musieli dokonać ponownej kompilacji.
Allain Lalonde
63
Super późno tutaj, ale: To nie ma znaczenia w ogóle , jeśli IDE pozwala na zmianę nazwy czegoś łatwe. Kod korzystający z instancji jakiegoś typu nigdy nie powinien dbać o to, czy ten typ jest interfejsem, klasą czy czymkolwiek innym. Dlatego ujawnienie takiego szczegółu w nazwie tego typu jest bezcelowe i szkodliwe dla zrozumienia. Liczy się rodzaj i umowa, którą wystawia!
ColinD
11
Poza tym, jeśli wybierasz się na drogę IFoo, nie powinno to być CFoo do implementacji i oczywiście w przypadku niepowodzenia metoda rzuci EFoo.
Robin
57
„Przedrostek szkodzi czytelności” jest czysto subiektywny. Podobnie jak większość konwencji nazewnictwa. Ważniejsze jest, aby Twój zespół uzgodnił, co zrobić, aby baza kodu była spójna.
dreadwail,
121

Czy naprawdę jest różnica między:

class User implements IUser

i

class UserImpl implements User

jeśli wszystko, o czym mówimy, to konwencje nazewnictwa?

Osobiście wolę NIE poprzedzać interfejsu, Iponieważ chcę kodować do interfejsu i uważam, że jest to ważniejsze z punktu widzenia konwencji nazewnictwa. Jeśli wywołasz interfejs, IUserkażdy konsument tej klasy musi znać jego interfejs IUser. Jeśli zadzwonisz do klasy, UserImpltylko klasa i twój kontener DI wiedzą o tej Implczęści, a konsumenci po prostu wiedzą, że pracują zUser .

Z drugiej strony czasy, których zmuszono mnie użyć, Implponieważ lepsza nazwa się nie przedstawia, były rzadkie, ponieważ implementacja jest nazywana zgodnie z implementacją, ponieważ jest to ważne, np.

class DbBasedAccountDAO implements AccountDAO
class InMemoryAccountDAO implements AccountDAO
tddmonkey
źródło
Myślę, że chciałbyś poznać jego DAO, ponieważ opisuje on ogólną funkcjonalność bez konieczności otwierania klasy. Jeśli przeglądam pliki klas w projekcie, łatwo jest zobaczyć wszystkie DAO, szukając * DAO
Patrick
6
DAO jest dobrze znanym wzorcem dostępu do bazy danych, więc posiadanie wzorca w nazwie ułatwia sprawdzenie, co robi klasa, po prostu patrząc na jej nazwę. PS Lepiej byłoby ściśle przestrzegać notacji wielbłąda („Accountdo”), na przykład w mina.apache.org/changes-between-2x-and-1x.html
Esko Luontola
4
@ Marker, to nie jest tak, że I wskazuje interfejs. DAO mówi ci, że klasa lub interfejs jest obiektem dostępu do danych konta, co właśnie robi ten obiekt. Posiadanie I mówi ci, że jest to interfejs, który nie ma nic wspólnego z samym obiektem, ale semantyką języka
tddmonkey 13.02.2009
Jak go prezentujesz, jego prefiks vs sufiks.
Andrei Rînea
3
@Andrei: Nie, to semantyka („DAO”) vs. niepotrzebna dekoracja artefaktu językowego („I” jak w interfejsie; fakt, który i tak jest wspomniany w kodzie „interfejs IFoo ...”)
Dirk
75

Może być kilka powodów, dla których Java zasadniczo nie korzysta z konwencji IUser.

  1. Częścią podejścia zorientowanego obiektowo jest to, że nie powinieneś wiedzieć, czy klient używa interfejsu czy klasy implementacji. Tak więc, nawet List jest interfejsem, a String jest rzeczywistą klasą, do obu metod można przekazać metodę - nie ma sensu wizualnie rozróżniać interfejsów.

  2. Ogólnie rzecz biorąc, wolimy używać interfejsów w kodzie klienta (na przykład wolą List od ArrayList). Dlatego nie ma sensu, aby interfejsy wyróżniały się jako wyjątki.

  3. Konwencja nazewnictwa Java preferuje dłuższe nazwy o rzeczywistych znaczeniach od prefiksów w stylu węgierskim. Aby ten kod był jak najbardziej czytelny: Lista reprezentuje listę, a Użytkownik reprezentuje użytkownika - nie użytkownika IUser.

Avi
źródło
72

Istnieje również inna konwencja, z której korzysta wiele projektów open source, w tym Spring.

interface User {
}

class DefaultUser implements User {
}

class AnotherClassOfUser implements User {
}

Osobiście nie podoba mi się prefiks „ja” z tego prostego powodu, że jest to opcjonalna konwencja. Jeśli więc to zrobię, czy IIOPConnection oznacza interfejs dla IOPConnection? Co jeśli klasa nie ma przedrostka „ja”, to czy wiem, że nie jest to interfejs… odpowiedź tutaj brzmi „nie”, ponieważ konwencje nie zawsze są przestrzegane, a ich przestrzeganie spowoduje więcej pracy niż sama konwencja.

ng.
źródło
Podoba mi się to, ponieważ pomaga także w korzystaniu z interfejsów dla zewnętrznych zależności zamiast łączenia klas.
Matt Briggs,
47

Jak powiedział inny plakat, zwykle lepiej jest, aby interfejsy definiowały możliwości, a nie typy. Nie chciałbym „implementować” czegoś takiego jak „Użytkownik” i dlatego „IUser” często nie jest tak naprawdę potrzebny w opisany tutaj sposób. Często widzę klasy jako rzeczowniki, a interfejsy jako przymiotniki:

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

Czasami przymiotnik nie ma sensu, ale nadal ogólnie używam interfejsów do modelowania zachowania, działań, możliwości, właściwości itp., A nie typów.

Ponadto, jeśli naprawdę chciałbyś stworzyć tylko jednego Użytkownika i nazwać go Użytkownikiem, to po co mieć interfejs IUser? A jeśli masz mieć kilka różnych typów użytkowników, którzy muszą wdrożyć wspólny interfejs, co dodanie „I” do interfejsu oszczędza ci przy wyborze nazw implementacji?

Wydaje mi się, że bardziej realistycznym przykładem jest to, że niektóre typy użytkowników muszą mieć możliwość zalogowania się do określonego interfejsu API. Moglibyśmy zdefiniować interfejs logowania, a następnie mieć klasę nadrzędną „Użytkownik” z sukkulami SuperUser, DefaultUser, AdminUser, AdministrativeContact itp., Z których niektóre będą, lub nie, w razie potrzeby implementować interfejs logowania (do zalogowania?).

nairbv
źródło
Myślę, że przykłady, które podajesz w celu wsparcia „interfejsów jako przymiotników”, są zniekształcone, ponieważ interfejsy te mają raczej przypominać wtyczki (lub cechy). Zatem interfejsy są dobre zarówno dla przymiotników, jak i rzeczowników - ale prawdopodobnie nie dla indefinite transitive verbs 8 ^ P
Stevel
To może ulec zmianie w ostatnich latach. Wyrocznia docu. zezwala na interfejsy jako typy: [link] docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
karlihnos
38

Bob Lee powiedział kiedyś w prezentacji:

jaki jest sens interfejsu, jeśli masz tylko jedną implementację.

więc zaczynasz od jednej implementacji, tj. bez interfejsu. później decydujesz, no cóż, potrzebny jest tutaj interfejs, więc przekonwertuj klasę na interfejs.

wtedy staje się oczywiste: twoja oryginalna klasa nazywała się Użytkownik. Twój interfejs nazywa się teraz Użytkownik. może masz UserProdImpl i UserTestImpl. jeśli dobrze zaprojektowałeś aplikację, każda klasa (z wyjątkiem tych, które tworzą użytkownika) pozostanie niezmieniona i nie zauważy, że nagle przejdzie interfejs.

więc staje się jasne -> Interfejs Implementacja użytkownika UserImpl.

Andreas Petersson
źródło
18
Korzystanie z interfejsów pomaga przetestować programowanie oparte na rozwoju. Napotkaliśmy wiele problemów związanych z brakiem modelu domeny i testowaniem, ponieważ postanowiliśmy NIE używać interfejsów. Mój przyjaciel kiedyś zacytował: „Wszystko jest interfejsem, na dłuższą metę uratuje cię”.
hooknc
4
Wyśmiewanie i łatwa obsługa proxy. Jestem pewien, że istnieją również inne powody, aby zapewnić interfejsy.
MetroidFan2002
3
Jak powiedziałem niedawno koledze, wprowadzenie interfejsu teraz nic nie kosztuje, ale później możesz zaoszczędzić sporo czasu.
tddmonkey
2
Jeśli możesz mieć inne implementacje w bliskiej środkowej przyszłości, interfejs byłby plusem.
Stef
3
Nie podoba mi się argument „Mogę potrzebować kolejnego impl w przyszłości”. Wolę podejście YAGNI: nie planuj rzeczy, które jeszcze się nie wydarzyły.
David Lavender,
24

W języku C # jest

public class AdminForumUser : UserBase, IUser

Java powiedziałaby

public class AdminForumUser extends User implements ForumUserInterface

Z tego powodu nie uważam, że konwencje są tak samo ważne w Javie dla interfejsów, ponieważ istnieje wyraźna różnica między dziedziczeniem a implementacją interfejsu. Powiedziałbym, że po prostu wybierz dowolną konwencję nazewnictwa, o ile chcesz, o ile jesteś konsekwentny i użyj czegoś, aby pokazać ludziom, że są to interfejsy. Nie robiłem java od kilku lat, ale wszystkie interfejsy będą po prostu w swoim katalogu i taka była konwencja. Nigdy tak naprawdę nie miałem z tym żadnych problemów.

Matt Briggs
źródło
22
Być może jestem złym koderem Java, ale wolę styl C #, co oznacza, że ​​wszystkie interfejsy zaczynają się od przedrostka „I” :)
davs
7
Nie jestem pewien, skąd ty i inni dostajecie tę rzekomą konwencję. W bibliotekach Java nie jest to widoczne ...
ChiefTwoPencils
6

Z mojego doświadczenia wynika, że ​​konwencja „ja” ma zastosowanie do interfejsów, które mają na celu zapewnienie kontraktu z klasą, szczególnie gdy sam interfejs nie jest abstrakcyjnym pojęciem klasy.

Na przykład w twoim przypadku spodziewam się tylko, IUserczy jedynym użytkownikiem, który kiedykolwiek zamierzasz mieć, jest User. Jeśli planujesz mieć różne typy użytkowników - NoviceUser, ExpertUseritp. - Spodziewałbym się Userinterfejsu (i być może AbstractUserklasy, która implementuje niektóre typowe funkcje, takie jak get/setName()).

Chciałbym również spodziewać interfejsy, które definiują możliwości - Comparable, Iterableitp - być nazwany tak, a nie jak IComparablealbo IIterable.

David Koelle
źródło
Jeśli jedynym użytkownikiem, który kiedykolwiek zamierzasz mieć, jest Użytkownik, dlaczego po prostu nie użyjesz Użytkownika zamiast interfejsu?
Carighan,
3
W niektórych architekturach klient / serwer strona po stronie musi znać interfejsy bez potrzeby implementacji ciężkich serwerów.
David Koelle,
5

Zgodnie z dobrymi zasadami OO, twój kod powinien (o ile to praktyczne / możliwe) zależeć od abstrakcji, a nie od konkretnych klas. Na przykład ogólnie lepiej jest napisać taką metodę:

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

od tego:

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

Jeśli zastosujesz się do tego pomysłu, utrzymuję, że twój kod będzie bardziej czytelny, jeśli podasz interfejsy takie jak „Użytkownik” i „Konto bankowe” (na przykład), a nie „IUser”, „Interfejs użytkownika” lub inne odmiany.

Jedynymi fragmentami kodu, które powinny zwracać uwagę na faktyczne konkretne klasy, są miejsca, w których budowane są konkretne klasy. Cała reszta powinna być napisana za pomocą interfejsów.

Jeśli to zrobisz, wówczas „brzydkie” konkretne nazwy klas, takie jak „UserImpl”, powinny być bezpiecznie ukryte przed resztą kodu, co można wesoło kontynuować przy użyciu „ładnych” nazw interfejsów.

KarstenF
źródło
Ale po co zawracać sobie głowę tworzeniem pasującego interfejsu dla każdej klasy w programie, gdy potrzebujesz tylko interfejsów dla jednej lub dwóch rzeczy?
LegendLength,
3

= v = Prefiks „I” jest także używany w frameworku Wicket, do którego szybko się przyzwyczaiłem. Ogólnie rzecz biorąc, z zadowoleniem przyjmuję każdą konwencję, która skraca nieporęczne nazwy klas Java. Problemem jest jednak to, że wszystko jest uporządkowane alfabetycznie pod „I” w katalogach i Javadoc.

Praktyka kodowania furtek jest podobna do Swinga, ponieważ wiele instancji sterujących / widgetów jest zbudowanych jako anonimowe klasy wewnętrzne z deklaracjami metod wbudowanych. Irytujące, różni się o 180 ° od Swing tym, że Swing używa przedrostka („J”) dla klas implementujących.

Przyrostek „Impl” jest złośliwym skrótem i nie jest dobrze umiędzynarodowiony. Gdybyśmy przynajmniej wybrali „Imp”, byłby ładniejszy (i krótszy). „Impl” jest używane w MKOl, szczególnie Spring, więc na razie utknęliśmy z tym. Jednak robi się trochę schizo po 3 różnych konwencjach w trzech różnych częściach jednej bazy kodu.

Jym Dyer
źródło
0

Czy jest to szersza konwencja nazewnictwa w jakimkolwiek realnym sensie? Jestem bardziej po stronie C ++, a tak naprawdę nie lubię Java i potomków. Ile społeczności językowych korzysta z konwencji I?

Jeśli masz tutaj standardową konwencję nazewnictwa sklepu niezależną od języka, skorzystaj z niej. Jeśli nie, przejdź do konwencji nazewnictwa języków.

David Thornley
źródło