Denominazione dell’interfaccia in Java

La maggior parte delle lingue OO prefigura i loro nomi di interfaccia con una I maiuscola, perché Java non lo fa? Qual è stata la ragione per non seguire questa convenzione?

Per dimostrare cosa intendo, se volessi avere un’interfaccia utente e un’implementazione utente avrei due possibilità in Java:

  1. Classe = Utente, Interfaccia = UserInterface
  2. Classe = UserImpl, Interface = User

Dove nella maggior parte delle lingue:

Classe = Utente, Interfaccia = IUser

Ora, si potrebbe obiettare che si potrebbe sempre scegliere un nome più descrittivo per l’implementazione dell’utente e il problema scompare, ma Java sta spingendo un approccio POJO alle cose e la maggior parte dei contenitori IOC usa estensivamente DynamicProxies. Queste due cose insieme significano che avrete molte interfacce con una singola implementazione POJO.

Quindi, suppongo che la mia domanda si riduca a: “Vale la pena seguire la più ampia convenzione di denominazione dell’interfaccia, specialmente alla luce di dove sembra che si stiano dirigendo i framework Java?”

Preferisco non usare un prefisso sulle interfacce:

  • Il prefisso fa male la leggibilità.

  • L’utilizzo delle interfacce nei client è il modo migliore di programmazione standard, pertanto i nomi delle interfacce dovrebbero essere il più brevi e gradevoli ansible. Le classi di implementazione dovrebbero essere più brutte per scoraggiare il loro uso.

  • Quando si passa da una class astratta a un’interfaccia, una convenzione di codifica con prefisso I implica la ridenominazione di tutte le occorrenze della class — non va bene!

C’è davvero una differenza tra:

 class User implements IUser 

e

 class UserImpl implements User 

se tutto ciò di cui stiamo parlando è la denominazione delle convenzioni?

Personalmente preferisco NON precedere l’interfaccia con I come voglio codificare per l’interfaccia e ritengo che sia più importante in termini di convenzione di denominazione. Se chiami l’interfaccia IUser ogni consumatore di quella class deve conoscerne un IUser . Se chiami la class UserImpl solo la class e il tuo contenitore DI conoscono la parte Impl e i consumatori sanno che stanno lavorando con un User .

Poi di nuovo, i tempi in cui sono stato costretto a usare Impl perché un nome migliore non si presenta sono stati pochi e distanti tra loro perché l’implementazione viene denominata in base all’implementazione perché è lì che è importante, ad esempio

 class DbBasedAccountDAO implements AccountDAO class InMemoryAccountDAO implements AccountDAO 

Ci possono essere diversi motivi per cui Java generalmente non usa la convenzione IUser.

  1. Parte dell’approccio orientato agli oggetti è che non dovresti sapere se il client sta usando un’interfaccia o una class di implementazione. Quindi, anche List è un’interfaccia e String è una class effettiva, un metodo potrebbe essere passato entrambi – non ha senso distinguere visivamente le interfacce.

  2. In generale, in realtà preferiremo l’uso delle interfacce nel codice client (preferiamo List ad ArrayList, ad esempio). Quindi non ha senso far risaltare le interfacce come eccezioni.

  3. La convenzione di denominazione Java preferisce nomi più lunghi con significati effettivi ai prefissi in stile ungherese. In modo che il codice sia il più leggibile ansible: un elenco rappresenta un elenco e un utente rappresenta un utente, non un utente.

C’è anche un’altra convenzione, utilizzata da molti progetti open source tra cui Spring.

 interface User { } class DefaultUser implements User { } class AnotherClassOfUser implements User { } 

Personalmente non mi piace il prefisso “I” per il semplice motivo che è una convenzione opzionale. Quindi, se adotto questo, IIOPConnection significa un’interfaccia per IOPConnection? Cosa succede se la class non ha il prefisso “I”, allora so che non è un’interfaccia … la risposta qui è no, perché le convenzioni non vengono sempre seguite, e la loro sorveglianza creerà più lavoro che la convenzione stessa salva.

Come è stato detto da un altro poster, è in genere preferibile che le interfacce definiscano le funzionalità e non i tipi. Tenderei a non “implementare” qualcosa come un “Utente”, ed è per questo che “IUser” spesso non è realmente necessario nel modo descritto qui. Spesso vedo le classi come nomi e interfacce come aggettivi:

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

A volte un Adjective non ha senso, ma in genere utilizzerei le interfacce per modellare comportamenti, azioni, capacità, proprietà, ecc., Non tipi.

Inoltre, se stavi davvero creando un solo utente e lo chiami utente, allora che senso ha anche un’interfaccia IUser? E se hai intenzione di avere diversi tipi di utenti che hanno bisogno di implementare un’interfaccia comune, che cosa fa l’aggiunta di un “io” all’interfaccia ti salva nella scelta dei nomi delle implementazioni?

Penso che un esempio più realistico sarebbe che alcuni tipi di utenti devono essere in grado di accedere a una particolare API. Potremmo definire un’interfaccia di login e quindi avere una class genitore “Utente” con le sottoclassi SuperUser, DefaultUser, AdminUser, AdministrativeContact, etc, alcune delle quali implementeranno o meno l’interfaccia di Login (Loginabile?) Secondo necessità.

Bob Lee ha detto una volta in una presentazione:

qual è il punto di un’interfaccia se hai una sola implementazione.

così, si inizia con un’implementazione cioè senza un’interfaccia. in seguito decidi, beh, c’è bisogno di un’interfaccia qui, quindi converti la tua class in un’interfaccia.

allora diventa ovvio: la tua class originale era chiamata User. la tua interfaccia è ora chiamata User. forse hai un UserProdImpl e un UserTestImpl. se hai progettato bene la tua applicazione, ogni class (eccetto quelle che istanziano l’Utente) rimarrà invariata e non si accorgerà che improvvisamente viene passata un’interfaccia.

quindi diventa chiaro -> Implementazione User Interface UserImpl.

In C # lo è

 public class AdminForumUser : UserBase, IUser 

Direbbe Java

 public class AdminForumUser extends User implements ForumUserInterface 

Per questo motivo, non credo che le convenzioni siano altrettanto importanti in Java per le interfacce, poiché esiste una differenza esplicita tra ereditarietà e implementazione dell’interfaccia. Direi semplicemente di scegliere qualsiasi convenzione di denominazione che desideri, a patto che tu sia coerente e usi qualcosa per mostrare alla gente che queste sono interfacce. Non ho fatto java in pochi anni, ma tutte le interfacce sarebbero state nella loro directory, e quella era la convenzione. Non ho mai avuto problemi con questo.

Nella mia esperienza, la convenzione “I” si applica alle interfacce che intendono fornire un contratto a una class, in particolare quando l’interfaccia stessa non è una nozione astratta della class.

Ad esempio, nel tuo caso, mi aspetterei di vedere IUser solo se l’unico utente che hai intenzione di avere è User . Se si prevede di avere diversi tipi di utenti: NoviceUser , ExpertUser , ecc., Mi aspetto di vedere un’interfaccia User (e, forse, una class AbstractUser che implementa alcune funzionalità comuni, come get/setName() ).

Mi aspetto anche che le interfacce che definiscono le funzionalità – Comparable , Iterable , ecc. – siano denominate in questo modo e non come IComparable o IIterable .

Seguendo i buoni principi OO, il tuo codice dovrebbe (per quanto pratico / ansible) dipendere dalle astrazioni piuttosto che dalle lezioni concrete. Ad esempio, in genere è meglio scrivere un metodo come questo:

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

di questo:

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

Se segui questa idea, allora ritengo che il tuo codice sarà più leggibile se fornisci nomi di interfacce come “Utente” e “BankAccount” (ad esempio), piuttosto che “IUser”, “UserInterface” o altre varianti.

Gli unici bit di codice che dovrebbero interessare le effettive classi concrete sono i luoghi in cui sono costruite le classi concrete. Tutto il resto dovrebbe essere scritto usando le interfacce.

Se si esegue questa operazione, i “brutti” nomi di classi concreti come “UserImpl” dovrebbero essere nascosti in modo sicuro dal resto del codice, che può tranquillamente continuare a utilizzare i nomi di interfaccia “belli”.

= v = Il prefisso “I” è usato anche nel framework Wicket, dove mi sono abituato velocemente. In generale, accolgo con favore qualsiasi convenzione che accorcia i complessi nomi di classi Java. È una seccatura, però, che tutto è alfabetizzato sotto “I” nelle directory e nel Javadoc.

La pratica di codifica di Wicket è simile a Swing, in quanto molte istanze di controllo / widget sono costruite come classi interne anonime con dichiarazioni di metodo inline. Fastidiosamente, differisce di 180 ° da Swing in quanto Swing utilizza un prefisso (“J”) per le classi di implementazione.

Il suffisso “Impl” è una abbreviazione mangly e non internazionalizza bene. Se solo fossimo andati con “Imp” sarebbe più carino (e più corto). “Impl” è usato per il CIO, in particolare per la spring, quindi per il momento siamo un po ‘bloccati. Tuttavia, diventa un po ‘schizo seguendo 3 diverse convenzioni in tre parti differenti di un codice base.

Si tratta di una convenzione di denominazione più ampia in senso reale? Sono più sul lato C ++, e non realmente su Java e discendenti. Quante comunità linguistiche usano la convenzione I?

Se hai una convenzione di denominazione standard del negozio indipendente dalla lingua qui, usala. In caso contrario, vai con la convenzione di denominazione della lingua.