Interfacce ovunque? - Best Practices [duplicate]

2

C'è una discussione sul lavoro sull'uso corretto delle interfacce in OOP. Mi è stato insegnato e ho sempre lavorato partendo dal presupposto che le interfacce precedono le concrezioni e che tutti i metodi dovrebbero essere trattati nei contratti. Mi sto disaccoppiando 101.

Ho scoperto che l'applicazione di questo schema insegna universalmente agli sviluppatori junior le corde, mi prepara al successo lungo la strada ("oh, tutto questo è strettamente accoppiato! Non posso usare nulla di tutto questo!"), e prende pochissimo tempo. È semplice (e utile) capire che noi, sempre, trattiamo i contratti.

Un altro collega sta dicendo che l'astrazione dovrebbe essere applicata solo quando ci sono più implementazioni e che farlo tutto il tempo rende le cose confuse per la squadra. Per me, non mi interessa, D è solo confuso all'inizio e diventa rapidamente una seconda natura, e per me è solo il modo corretto di costruire.

Ma volevo raggiungere e vedere se qualcuno poteva fornire alcuni riferimenti / testi di esperti che spiegavano perché o perché no.

    
posta froodley 07.06.2018 - 01:58
fonte

5 risposte

6

Non voglio nemmeno sapere se sto usando un'interfaccia (il tipo di parola chiave). La mia funzione di guida prende una macchina. Se questo è concreto o meno non è uno dei suoi affari.

Questo è il motivo per cui sono infastidito dalla convenzione ICar di C #. Ottieni quel rumore inutile di I dalla mia faccia. Java non è molto meglio. Oh certo, per convenzione, mi è permesso di nominare un'interfaccia, una classe astratta o una classe concreta Car nel codice sorgente, ma se cambio da una all'altra devo ricompilare tutto ciò che la usa!

Tutto quello che voglio è esprimere quali sono le esigenze di drive() s nel sistema di tipi. Non desidero che drive() sappia di cosa sta parlando oltre a sapere che qualunque cosa sia, sa come ascoltare.

A proposito, se hai dei buoni test, una lingua con digitazione anatra ti dà tutto questo gratuitamente.

Ma dal momento che devo usare queste lingue così come le trovo, tendo ad usare interfacce di ruolo in loro. Il che significa che non scrivo drive(Car car) Scrivo drive(DriverControls driverControls) e qualsiasi cosa voglia accettare sterzare, accelerare e rompere i messaggi sul protocollo DriverControls è libera di farlo.

Quindi se è quello di cui stai parlando sono con te. Se sei uno di quei fanatici che insiste su ogni classe come Car ha una contropartita ICar puoi saltare in un lago.

    
risposta data 07.06.2018 - 05:19
fonte
3

Sono d'accordo con il tuo collega.

Creare buone astrazioni è difficile. Come, davvero, davvero HARD!

Le astrazioni aggiungono complessità al software. Rendono più difficile navigare il codice e ragionare su di esso. Rendono le cose più difficili da cambiare, poiché le modifiche alle astrazioni richiedono spesso modifiche in più punti.

Un'interfaccia che copia solo i metodi della classe non è una buona astrazione. Solo il tempo che puoi dire che hai una buona astrazione è che puoi immaginare (o avere in realtà) più implementazioni diverse.

Ogni volta che crei un'astrazione, devi farti una domanda "Vale davvero la pena complicare il codice in modo da poter disaccoppiare questi pezzi?"

    
risposta data 07.06.2018 - 07:52
fonte
3

Ti manca una grande parte del puzzle:

L'uso delle interfacce in ogni parte del mondo rende il tuo codice molto più difficile da navigare

Supponiamo che tu abbia una grande base di codice con centinaia di classi che è cresciuta nel corso degli anni.

Di solito, quando vuoi sapere cosa succede in un metodo, basta fare clic su di esso e l'IDE salterà al suo codice ... cioè, se si tratta di una classe. Se si tratta di un'interfaccia, si passerà all'interfaccia, quindi si dovrà capire quale classe è instanciata, e questo potrebbe richiedere un po 'di tempo, e andare lì, e andare dentro un altro dei suoi metodi e di nuovo atterrare su un'interfaccia, quindi devi capire di nuovo cosa è stato effettivamente instanciato, che può richiedere un po 'di tempo, ecc.

Fondamentalmente, la navigazione nel codice diventa sempre più frustrante a causa delle interfacce superflue.

La mia regola empirica: usa un'interfaccia quando in effetti hai più implementazioni diverse dietro, non solo per il gusto di farlo .

EDIT:

Il mio "molto più difficile" è stato probabilmente esagerato. Dovrei semplicemente aver scritto "più difficile" o "non regolare".

Per illustrare questo, in eclissi. Con un metodo di una classe:

  • Ctrl + clic salta all'interno del metodo (1 clic).

Con un metodo da un'interfaccia, sarebbe:

  • Ctrl + clic
  • vai in alto
  • tasto destro sul nome dell'interfaccia
  • apri type explorer
  • seleziona la classe
  • apri schema
  • vai al metodo

... Quindi, si, puoi farlo con un buon supporto IDE, ma è comunque abbastanza fastidioso.

    
risposta data 07.06.2018 - 10:50
fonte
1

Il disaccoppiamento non è una cosa buona da sola. È solo una buona cosa dove ne hai bisogno, e cattiva ovunque. Se stai usando un'interfaccia in un posto dove dovrebbe essere alta coesione, allora stai sbagliando.

Ogni interfaccia ha un costo e un valore, se non la stai prendendo in considerazione e ciecamente li costruisci ovunque, allora stai semplicemente sbagliando.

    
risposta data 07.06.2018 - 14:00
fonte
0

Programma applicazioni aziendali di dati

Di solito non sono disponibili per il classico OOP "vero" in cui l'oggetto implementa il proprio comportamento a causa di tutte le regole aziendali che dipendono dall'attuale utente connesso e così via. Invece ho i ben noti servizi anemici di modello +, perché non ho trovato nulla che si adatta meglio alle mie esigenze, tranne che per alcuni componenti tecnici indipendenti.

I miei servizi hanno sempre interfacce, perché anche se ho un'implementazione, ci sarà un momento in cui voglio prenderli in giro. Io astraggo un po 'ma non troppo da quando lo faccio, non so quanto potrei aver bisogno e come farlo correttamente, e il mio tempo è meglio spendere che perdere tempo su questo (YAGNI / KISS ).

Naturalmente, dal momento che comincio con una sola implementazione, la mia interfaccia è praticamente una copia di ciò che la mia implementazione deve esporre ma è apposta. Se ho bisogno di un'altra implementazione che, per sua natura, costringerà il mio a ridirigere la mia interfaccia a una più generica, e lo farò quando sarà necessario.

Nota: uso un nome normale per l'interfaccia dei miei servizi che uso (non "I" o qualsiasi altra cosa), perché il consumatore di quei servizi non si preoccupa davvero delle loro interfacce come ha detto @candied_orange

    
risposta data 07.06.2018 - 14:14
fonte

Leggi altre domande sui tag