Perché Java consente di implementare interfacce diverse, ciascuna contenente un metodo con la stessa firma?

5

Recentemente ho scoperto che posso avere due interfacce, una contenente un metodo con la stessa firma di un metodo nell'altra interfaccia. E posso avere un'interfaccia o una classe che implementa entrambe le interfacce citate in precedenza. Quindi la classe / interfaccia discendente implementa implicitamente due metodi diversi come un metodo.

Perché è permesso in Java?

Riesco a vedere numerosi problemi derivanti da questo. Eclipse, ad esempio, può solo scoprire le implementazioni per un metodo di interfaccia, ma per il secondo non mostra alcuna implementazione. Inoltre, credo che ci sarebbero problemi con il refactoring automatico, come quando si vuole cambiare la firma del metodo in una delle interfacce e l'IDE non sarà in grado di cambiare correttamente quella firma in tutte le implementazioni (poiché implementano due interfacce diverse e l'IDE non può dire a quale metodo di interfaccia si riferisce l'implementazione.)

Perché non fare solo un errore del compilatore come "i nomi dei metodi delle interfacce si scontra" o qualcosa del genere?

    
posta dhblah 28.11.2012 - 12:29
fonte

5 risposte

23

Non c'è motivo per cui questo dovrebbe essere vietato. L'unico punto di un'interfaccia è garantire che esista un metodo con firma particolare in ogni classe di implementazione. Questo è soddisfatto da qualsiasi classe di implementazione anche se la condizione è posta due volte.

Certo, quando si scrive un'interfaccia presumibilmente ci si aspetta un certo significato per l'azione di invocare il metodo, e presumibilmente lo si documenta sopra la dichiarazione nell'interfaccia, ma questa non è la preoccupazione di il compilatore. Non può controllare se la classe di implementazione fa la cosa giusta, solo se copia esattamente la firma. Chiedere "Perché il compilatore non proibisce un metodo per soddisfare due dichiarazioni di interfaccia?" si riduce a "perché il compilatore non mi impedisce di implementare la semantica sbagliata quando implemento un'interfaccia?", e la risposta a questa domanda è molto più facile da vedere: perché non può! (Se il compilatore fosse in grado di giudicare l'implementazione del metodo e vietarlo se contenesse un bug, in primo luogo non avremmo bisogno dei programmatori, avremmo bisogno solo delle specifiche e del compilatore.)

Ovviamente ci piacerebbe che l'implementazione di un'interfaccia garantisca che la classe di implementazione fa la cosa giusta, ma non è qualcosa che le interfacce possono fare per te. In realtà, direi che sarebbe una brutta cosa aggiungere una funzione al compilatore che potrebbe dare l'impressione che sia!

    
risposta data 28.11.2012 - 12:52
fonte
6

Perché dovrebbe essere una brutta cosa?

Solo perché rende più difficile il refactoring in Java, non significa che sia cattivo. Ad esempio, se voglio refactoring in C ++, sarebbe quasi impossibile nei casi di un codice pesante dipendente da template, dato che i template sono completi di Turing. E in C ++, i modelli sono come la cosa migliore nella lingua. Dovremmo rimuoverli per rendere più facile il refactoring?

La principale preoccupazione nella progettazione della lingua dovrebbe essere quella di rendere più semplice la vita / il lavoro dei suoi utenti. Penso che la tua regola sia troppo stretta e non intuitiva in questo senso.

In più questo mi sembra troppo severo: ad esempio sto usando due librerie, closed source (per quanto è possibile in Java comunque). Ho una classe che ha bisogno di implementare due interfacce, una per ogni libreria. Ma le interfacce hanno un metodo con lo stesso nome / firma.

Secondo la tua logica, sono condannato! E a pensarci bene, i progettisti della biblioteca non hanno fatto nulla di sbagliato: è loro compito conoscere i tutti nomi dei metodi nelle tutte classi di tutte altre librerie ? Non c'è alcuna possibilità di garantire questo, anche se ci provi ...

Si potrebbe dire che questo dovrebbe essere diviso in due classi, ma cosa succederebbe se i progettisti di librerie effettivamente intendessero la stessa cosa con i due metodi? Avere una classe implementare entrambe le interfacce è il modo corretto in questa situazione.

    
risposta data 28.11.2012 - 12:50
fonte
5

Tecnicamente non c'è nulla di sbagliato in questo dal punto di vista della lingua. Ci sarebbero stati problemi se avessi ereditato da due classi, dove sono implementate le classi base.

Se lo consideri un problema di progettazione in cui un'interfaccia ha un contratto per quel metodo e l'altra interfaccia ha un altro contratto che non consente che non risolva il problema. La soluzione finale sarebbe disabilitare l'ereditarietà multipla.

Riguardo al problema del refactoring automatico, c'è un problema con l'IDE (Intellij ha lo stesso comportamento); dovrebbe chiederti quale metodo di base vuoi refactored.

    
risposta data 28.11.2012 - 12:51
fonte
1

Bene, io sono più di un ragazzo .Net ma ho pensato di chipping.

Quindi, perdonami se la sintassi non è corretta.

Supponi di dover parlare con due diversi DB nella tua classe. Ogni DB ha un'interfaccia diversa.

interface IOldDB
{
   string GetConnectionString()
   void OpenConnection()
   void OpenSession()
   ...
}

interface IOldDB
{
   string GetConnectionString()
   bool Connect()
   void NewSession()
   ...
}

Rendere illegale significherebbe che dovrei avere due classi, una per Interfaccia. Tutto perché un metodo "apparentemente" in conflitto.

E se i metodi di alcune interfacce hanno la stessa firma e stai implementando entrambi, probabilmente ci sono per lo stesso motivo, giusto? In caso contrario, probabilmente stai violando l'SRP. Anche se lo stai violando, non c'è motivo per il compilatore di fermarti.

A proposito, se non sbaglio, il compilatore genererà un errore se la firma di uno dei metodi è in conflitto. Cercando di implementare queste due interfacce

interface IAnotherDB
{
   void GetConnectionString(string cs)
}

interface IYetAnotherDB
{
   void GetConnectionString(string ConnectionString)
}

Genera un errore.

In .Net è possibile farlo implementando l'interfaccia in modo esplicito.

Invece di:

public void GetConnectionString(string ConnectionString)

Potresti fare

IAnotherDB.GetConnectionString(string cs) 
IYetAnotherDB.GetConnectionString(string ConnectionString)

E continua.

Spero che ti aiuti.

    
risposta data 29.11.2012 - 04:29
fonte
0

Sembra che implichi una certa pigrizia, ma in realtà non è un problema.

Se hai due interfacce, ognuna con i metodi necessari per un determinato scenario, è necessario che entrambe le interfacce si implementino a vicenda, esegui il cast tra loro (yuck) o chiedi loro di dichiarare ridondanti i rispettivi metodi.

Immagino di poter immaginare casi in cui l'estensione non era pratica o possibile, quindi forse in questo caso sceglieresti l'opzione che stai descrivendo.

Il modo migliore per farlo sarebbe probabilmente l'ereditarietà dell'interfaccia in cui un'interfaccia potrebbe implementare 2 o 3 interfacce più specifiche, ma questo potrebbe infastidire molte persone ...

    
risposta data 28.11.2012 - 18:53
fonte

Leggi altre domande sui tag