Default vs Impl durante l'implementazione di interfacce in Java


34

Dopo la lettura I nomi dei pacchetti devono essere singolari o plurali? mi è venuto in mente che non ho mai visto un dibattito adeguato su uno dei miei animali domestici: denominare le implementazioni delle interfacce.

Supponiamo che tu abbia un'interfaccia Orderche deve essere implementata in vari modi, ma c'è solo l'implementazione iniziale al momento della creazione del progetto. Non si va per DefaultOrdero OrderImplo qualche altra variante per evitare la falsa dicotomia? E cosa fai quando arrivano più implementazioni?

E soprattutto ... perché?

Risposte:


59

I nomi hanno l'opportunità di trasmettere significato. Perché perdere questa opportunità con Impl?

Prima di tutto, se avrai sempre una sola implementazione, elimina l'interfaccia. Crea questo problema di denominazione e non aggiunge nulla. Ancora peggio, potrebbe causare problemi con firme del metodo incoerenti nelle API se tu e tutti gli altri sviluppatori non state attenti a usare sempre solo l'interfaccia.

Detto questo, possiamo supporre che ogni interfaccia abbia o possa avere due o più implementazioni.

  • Se ne hai solo uno in questo momento e non sai in che modo l'altro potrebbe essere diverso, Default è un buon inizio.

  • Se ne hai due in questo momento, nominali ciascuno secondo il suo scopo.

    Esempio: recentemente abbiamo avuto un contesto di classe concreto (in riferimento a un database). Ci siamo resi conto che dovevamo essere in grado di rappresentare un contesto offline, quindi il nome Context è stato usato per una nuova interfaccia (per mantenere la compatibilità con le vecchie API) e una nuova implementazione è stata creata, OfflineContext . Ma indovina come è stato rinominato l'originale? Esatto, ContextImpl (yikes).

    In questo caso, DefaultContext sarebbe probabilmente ok e la gente lo otterrebbe, ma non è così descrittivo come potrebbe essere. Dopo tutto, se non è offline , che cos'è? Quindi siamo andati con: OnlineContext .


Caso speciale: utilizzo del prefisso "I" sulle interfacce

Una delle altre risposte ha suggerito di utilizzare il prefisso I sulle interfacce. Preferibilmente, non è necessario farlo.

Tuttavia, se hai bisogno sia di un'interfaccia, per implementazioni personalizzate, ma hai anche un'implementazione concreta primaria che verrà utilizzata spesso e il nome di base è troppo semplice per rinunciare a un'interfaccia da solo, quindi puoi considerare di aggiungere "Io" all'interfaccia (tuttavia, va benissimo se non si adatta perfettamente a te e al tuo team).

Esempio: molti oggetti possono essere un "EventDispatcher". Per motivi di API, questo deve essere conforme a un'interfaccia. Tuttavia, si desidera anche fornire un dispatcher di eventi di base per la delega. DefaultEventDispatcher andrebbe bene, ma è un po 'lungo e se ne vedrai spesso il nome, potresti preferire utilizzare il nome base EventDispatcher per la classe concreta e implementare IEventDispatcher per implementazioni personalizzate:

/* Option 1, traditional verbose naming: */
interface EventDispatcher { /* interface for all event dispatchers */ }
class DefaultEventDispatcher implements EventDispatcher {
  /* default event dispatcher */
}

/* Option 2, "I" abbreviation because "EventDispatcher" will be a common default: */
interface IEventDispatcher { /* interface for all event dispatchers */ }
class EventDispatcher implements IEventDispatcher {
  /* default event dispatcher. */
}

3
+1 per una risposta solida. Come il ragionamento dietro non usare Impl.
Gary Rowe,

2
+1 assolutamente d'accordo. Nominare un'interfaccia lontana dal concetto di dominio che rappresenta manca del tutto.
Rupjones,

9
"se avrai mai una sola implementazione", come fai a sapere in anticipo che avrai una sola implementazione? "ogni interfaccia ha o può avere due o più implementazioni" ... prima di avere due implementazioni, non ne hai prima nessuna, quella che hai una, poi ne hai due, voglio dire che può esserci un momento in cui hai una sola implementazione, solo prima di implementare il secondo.
Tulains Córdova,

2
@NickC Non sono pedante per la semantica (sono un poeta e non lo sapevo nemmeno). L'inglese non è la mia lingua madre, quindi non posso essere pedante al riguardo. Stavo parlando di logica imperfetta. Si utilizzano interfacce per il disaccoppiamento. Ciò non richiede un certo numero di implementazioni.
Tulains Córdova,

4
if you will only ever have one implementation, do away with the interface- a meno che tu non voglia testare il componente nel qual caso potresti voler mantenere quell'interfaccia per creare MockOrder, OrderStub o simili.
JBR Wilkinson,

15

Decido la denominazione in base al caso d'uso dell'interfaccia.

Se l'interfaccia viene utilizzata per il disaccoppiamento , allora scelgo Implper le implementazioni.

Se lo scopo dell'interfaccia è l' astrazione comportamentale , le implementazioni vengono denominate in base a ciò che stanno concretamente facendo. Aggiungo spesso il nome dell'interfaccia a quello. Quindi, se l'interfaccia viene chiamata Validator, io uso FooValidator.

Trovo che Defaultsia una pessima scelta. Innanzitutto inquina le funzionalità di completamento del codice, poiché i nomi iniziano sempre con esso. L'altra cosa è che un valore predefinito è soggetto a modifiche nel tempo. Quindi ciò che prima potrebbe essere un valore predefinito può qualche tempo dopo essere una funzionalità obsoleta. Quindi o inizi sempre a rinominare le tue classi non appena le impostazioni predefinite cambiano o vivi con nomi fuorvianti.


8

Sono d'accordo con la risposta di Nicole (in particolare che l'interfaccia probabilmente non è necessario nella maggior parte dei casi), ma per il bene della discussione mi butto fuori un ulteriore alternativa diversa OrderImple DefaultOrder: nascondere l'implementazione dietro un metodo factory statico come Orders.create(). Per esempio:

public final class Orders {
  public static Order create() {
    return new Order() {
      // Implementation goes here.
    };
  }
}

Con questo approccio, l'implementazione potrebbe essere una classe interna anonima, oppure potrebbe essere una classe privata con Defaulto Implnel nome, oppure potrebbe essere nominata in modo completamente diverso. Qualunque sia la scelta fatta, il chiamante non ha bisogno di cure, quindi avrai più flessibilità ora e in seguito quando / se decidi di cambiarlo.

Alcuni ottimi esempi di questo modello in pratica sono le classi di utilità java.util.Collectionse java.util.concurrent.Executors, i cui metodi restituiscono implementazioni nascoste. Come cita efficace Java (nell'articolo 1), questo modello può aiutare a ridurre il "Peso concettuale" dell'API.


+1 per un caso aggiuntivo interessante: implementazioni anonime.
Gary Rowe,

1
Utilizzato ampiamente anche in guava .
Nicole,

3

Vado sempre OrderImplsemplicemente perché si presenta in ordine alfabetico subito dopo l' Orderinterfaccia.


2
E come gestire le ulteriori implementazioni in corso, per una gestione speciale e così via?
Gary Rowe,

1
Hai chiesto informazioni sull'implementazione iniziale. Una volta che inizi a implementare DomesticOrder, ForeignOrder o qualsiasi altra cosa, vengono nominati in modo più ponderato e indipendentemente dalla loro posizione nell'alfabeto.
Ben Hoffstein,

Esatto, ho modificato la domanda originale per riflettere questo nuovo requisito.
Gary Rowe,

Non è una buona idea Se ci sarà più di una implementazione.
Sadegh,

0

Puoi nominare l'interfaccia con il prefisso I (IWhatever) e quindi implementare qualunque cosa.

Le convenzioni ufficiali sul codice Java non parlano di questo tipo di denominazione per le interfacce, tuttavia questo tipo di denominazione aiuta il riconoscimento e la navigazione.


Perché dovresti prefissare l'interfaccia con un I? Aiutare il riconoscimento nella navigazione?
Gary Rowe,

@Gary: prefissare i tipi di interfaccia con I è una convenzione consolidata nel linguaggio Delphi. In Delphi i tipi di classe hanno il prefisso T. Quindi avremmo un'interfaccia IOrder e un'implementazione predefinita TOrder con TSomethingOrder e TBullMarketOrder come implementazioni specifiche.
Marjan Venema,

3
Ho visto questa convenzione utilizzata anche nello sviluppo di .NET. Forse perché la documentazione e gli esempi di Microsoft lo usano.
Ben Hoffstein,

5
Sembra che @Renesis abbia trovato un caso utile per usarlo all'interno di Java. Personalmente, farei affidamento sull'IDE per dirmi la differenza, altrimenti avremmo E per Enum, C per classi e tutti in gran parte ridondanti.
Gary Rowe,

0

Penso che mentre Default può avere senso in alcuni casi, sarebbe più utile descrivere l'implementazione. Quindi, se l'interfaccia è UserProfileDAOallora la vostra implementazioni possono essere UserProfileSQLDAOo UserProfileLDAPDAOo qualcosa del genere.


0

se possibile, chiamalo dopo cosa / come fa la sua cosa.

di solito l'approccio peggiore è chiamarlo come deve essere usato.

Se si suppone che venga utilizzato come classe base per l'implementazione, è possibile utilizzare BaseX o AbstractX (se è astratto (ma provare a fare lo squeze in quello che fa, perché se non facesse nulla non lo avresti creato, lo hai già interfaccia) Se fornisce la funzionalità più semplice possibile e si prevede che venga utilizzato direttamente (non estendendolo) quando tale funzionalità è sufficiente, è possibile chiamarlo SimpleX o BasicX.

Se viene utilizzato a meno che non venga fornita un'altra implementazione, denominarlo DefaultX


-2

La maggior parte di queste risposte descrive ciò che viene fatto, ma non il perché.

Che cosa è successo ai principi OO? Cosa mi dice Impl di una lezione e come usarla? Dovresti preoccuparti di comprendere gli usi e non il modo in cui è costruito.

Se creo un'interfaccia Person, che cos'è un PersonImpl? Senza senso. Almeno DefaultPerson mi dice che chiunque lo abbia codificato non avrebbe dovuto creare un'interfaccia.

Le interfacce stanno digitando per il polimorfismo e dovrebbero essere usate come tali.


1
La risposta accettata da @NickC fornisce alcuni dettagli su ciò che viene fatto e perché.
Gary Rowe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.