Ha senso dichiarare campi privati usando un'interfaccia come loro tipo?

6

Per i campi che hai come membri incapsulati di una classe, ha senso dichiarare che il loro tipo sia dell'interfaccia che stai usando? Ad esempio:

public class PayrollInfo
{
  private Map<String, Employee> employees;

  public PayrollInfo()
  {
     employees = new HashMap<>();
  }
}

Questo ti dà la massima flessibilità in quanto puoi modificare facilmente l'implementazione della classe. Tuttavia, nella mia esperienza i programmatori normalmente dichiarano che le variabili sono del tipo esatto della classe che verrà loro assegnata, ad es. HashMap in questo caso. Perché è questo?

    
posta Paul Richards 07.05.2016 - 21:13
fonte

8 risposte

5

È molto sensato se si assegna loro un valore al di fuori della classe. Vale a dire.

public class Basket
{
    private IPurchaseService _pServ;
    public Basket(IPurchaseService pServ)
    {
        _pServ = pServ;
    }
}
    
risposta data 07.05.2016 - 23:33
fonte
3

in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them... Why is this?

IMO è perché stanno pensando al programma in modo semplicistico, non orientato agli oggetti. La maggior parte degli sviluppatori con cui lavoro andrebbero nell'altro modo e dichiarano la variabile come Map... invece di HashMap... perché quando stanno usando l'oggetto, sono interessati solo a sapere come si comporterà-- -Non è affatto interessato al tipo di oggetto in cui è .

Non è un grosso problema quando parli di una variabile privata che esiste solo all'interno di una singola classe, ma diventa un grosso problema quando diventa parte di un'API pubblica. I miei colleghi probabilmente rifiuterebbero il tuo esempio nella revisione del codice se avessi dichiarato la variabile come HashMap... . Non perché una dichiarazione di variabili private fosse importante per qualsiasi altra parte del sistema, ma perché lo consideravano un modo superficiale di pensare, e vorrebbero che tu prendessi l'abitudine di pensare a un livello più profondo.

    
risposta data 07.05.2016 - 21:45
fonte
2

Un programmatore che sta facendo questo probabilmente sta solo seguendo le migliori pratiche nell'uso dei tipi di interfaccia invece dei tipi concreti; tuttavia, qui non c'è alcun reale vantaggio nel farlo, anche perché è privato come hai notato. (In effetti, è possibile che ciò si traduca in una leggera penalizzazione delle prestazioni quando si utilizza il campo in seguito.)

Qualsiasi modifica di implementazione delle due righe di codice in questione (la riga che dichiara e la linea che inizializza) sarà versionata insieme, quindi sarebbe facile cambiare il tipo in qualcos'altro, se necessario.

Questa è un'area in cui potrebbe essere bello poter dichiarare i campi usando var (C # comunque).

L'utilizzo di var mantiene la maggior quantità possibile di informazioni sul tipo, una variabile locale dichiarata in questo modo: var employees = new HashMap() sarebbe un riferimento a un'istanza HashMap , che supporta anche l'interfaccia Map , senza dover effettivamente violare la best practice sull'uso delle interfacce per le dichiarazioni.

Vedi anche: La migliore pratica di "programmare interfacce" si applica alle variabili locali? . Come puoi leggere tu stesso, ci sono opinioni in entrambe le direzioni su questo. Penso che alcuni temano che se i programmatori non lo fanno per i locali, si dimenticheranno di seguire questa best practice quando conta davvero, come per i parametri e i parametri del metodo pubblico; tipi di valore di ritorno. YMMV.

    
risposta data 07.05.2016 - 21:29
fonte
2

A volte lo faccio perché l'implementazione dice all'utilizzatore della classe qualcosa di importante.

Un esempio potrebbe essere la classe C # denominata ConcurrentDictionary. A seconda di come lo sto usando, potrei usare il dizionario usando l'interfaccia di IDictionary, ma facendo ciò rende meno chiaro ai programmatori successivi che il dizionario è sicuro per i thread. (Questo esempio non si applica a Java, poiché ConcurrentMap è un'interfaccia, l'idea si applica)

    
risposta data 08.05.2016 - 01:45
fonte
2

Does it make sense to declare private fields using an interface as their type?

Sì, lo fa. Per molte ragioni.

However, in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them, e.g. HashMap in this case. Why is this?

Finché non hanno scritto completamente il metodo, non sanno a cosa servirà l'accesso. Si potrebbe iniziare con l'interfaccia più restrittiva e passare a meno restrittive in base alle esigenze. Ma funzionerà contro gli strumenti di completamento del codice.

Iniziando con HashMap come HashMap e successivamente passando all'interfaccia più restrittiva teoricamente si ottiene lo stesso risultato. E significa che, mentre pensi a nuove cose che ti servono da HashMap, sono a portata di mano. Il problema è che le persone che lavorano in questo modo a volte dimenticano di fare il passaggio.

Per alcuni è più facile pensare a una HashMap come solo una HashMap quando si scrive codice. Dopo tutto, ci sono molte altre cose a cui pensare. Anche alcuni programmatori OOP ben addestrati fanno questo, non perché pensano che sia una buona pratica, ma perché non vogliono essere distratti mentre scrivono il codice. Questo è egoista perché non li ferisce tanto quanto fa male a coloro che vengono dopo. A volte intendevano dedicare del tempo al refactoring dell'interfaccia, ma non ci sono riusciti. Non guardare il codice scritto in questo modo come se fosse pensato per essere in questo modo. Questo è veloce e sporco.

Ma è privato! No getter. Nessun setter.

È vero che essere privati significa questo tipo di variabili e la sua stessa esistenza non è visibile al mondo esterno a meno che non sia passato in qualche oggetto esterno. Anche in quel caso il parametro del metodo / costruttore che lo riceve è quello che più ha bisogno di essere il più alto possibile nella catena di ereditarietà. Non è passato l'argomento (la nostra variabile).

Tuttavia, i buoni principi di codifica non riguardano solo gli oggetti. Alcuni possono risparmiare un sacco di problemi con un solo metodo.

Principi di progettazione rilevanti

  1. Programma su un'interfaccia, non un'implementazione
  2. Interfacce ruolo
  3. Prendi le decisioni in un unico posto

Programma su un'interfaccia

Diciamo che questa variabile è utilizzata in almeno un lungo metodo difficile da leggere. Se è dichiarata come una mappa e non qualcosa di concreto, posso immediatamente dire che potrei rifattorizzare qualsiasi implementazione cartografica senza nemmeno dover leggere il lungo metodo.

Interfaccia ruoli

Se il metodo lungo può andare avanti con la variabile ad un livello ancora più alto dovrebbe. Hai davvero bisogno di una mappa? Riesci a cavartela con una delle sue super interfacce che espone di meno? (Beh, la mappa non ha un'interfaccia super ma immagina di parlare di lista). Meno esposto, più alto è, più opzioni hai per cambiare senza problemi.

Prendi le decisioni in un unico posto

Dato che ho già dimostrato di non voler nemmeno leggere questo lungo e brutto metodo, dovrebbe essere una sorpresa che io non voglia attraversarlo modificando una serie di hashmap da mappare? (o qualche altra implementazione se ho voglia di trasmettere la miseria). Io non. Io davvero no. Per favore, non farmi. Per favore?

    
risposta data 08.05.2016 - 03:28
fonte
1

Ricorda sempre l'estendibilità durante la codifica. L'utilizzo delle interfacce nei campi privati può essere un risparmio di tempo più avanti quando ...

  1. vuoi usare un setter per il campo. In questo modo l'utente del setter deve solo conformarsi all'interfaccia.
  2. vuoi cambiare l'implementazione all'interno della classe. Immagina un giorno di trovare un'implementazione più performante di Map rispetto a HashMap. Durante il refactoring è sufficiente cambiare il costruttore. Nessun problema con l'utilizzo di metodi specifici dell'implementazione.

La mia regola del pollice:

Se hai bisogno di alcune funzionalità dell'implementazione concreta, usalo, altrimenti rimani sull'interfaccia.

Si noti che questo si applica solo ai tipi built-in e alle librerie di terze parti. Per il tuo codice personale devi sapere dove si trova la tua API per il mondo esterno. Per evitare di cambiare entrambe le interfacce e le implementazioni, uso solo le implementazioni - finché non so di trarre benefici dalla generazione di interfacce dalle classi.

    
risposta data 08.05.2016 - 00:04
fonte
0

programmers normally declare variables to be of the exact type of the class that will be assigned to them

Nella mia esperienza, ci sono diversi motivi per questo:

  1. Il programmatore manca della comprensione / intuizione per riconoscere che Map è un'interfaccia di HashMap e non riesce a vedere che è anche una considerazione o un'opzione.

  2. Il programmatore si concentra sulla necessità di implementare un Map , non sulla flessibilità per possibili usi futuri che non sono ovvi.

  3. I guadagni di flessibilità non sono necessari o potrebbero persino aggiungere complessità a un'implementazione senza aggiungere valore sufficiente a giustificarlo (una forma di pre-ottimizzazione).

La terza situazione è la più importante, ma raramente la vedo. Vedo molti programmatori molto intelligenti che scrivono codice molto "intelligente" e "flessibile" e fanno qualcosa di simile a ciò che illustrate. Quindi, quando il codice viene mantenuto o deve essere modificato in futuro, tutti i programmatori validi e necessari ma non così intelligenti non hanno idea di cosa sia successo o di come sfruttarlo. Aggiunge complessità durante quelle fasi di aggiornamento e / o manutenzione future costose.

Quindi, potrebbe essere che un programmatore molto lungimirante che fosse perfettamente in grado di realizzare un'implementazione più flessibile, optasse invece per un'implementazione più diretta e più facile da mantenere fino a che le richieste future richiedessero un approccio più flessibile - e meglio determinato l'appropriato modo per implementare tale flessibilità (ad es. forse è necessaria una classe wrapper o un'implementazione personalizzata Map ).

does it make sense to declare their type to be of the interface that you are using?

In alcuni casi, è molto utile. Tuttavia, è improbabile che farlo senza un bisogno immediato possa "migliorare" il codice. Nell'esempio semplificato, la modifica della dichiarazione a un'interfaccia dovrebbe essere facile e ovvia quando necessario e pienamente compatibile. Nei casi più complessi, è probabilmente ancora meglio implementare solo ciò che è necessario.

Se, tuttavia, stai scrivendo il codice di sistema o il codice API, probabilmente stai andando nella giusta direzione se intendi esporre l'accesso a questa variabile in qualche modo e l'utente finale del codice potrebbe avere necessità al di là di ciò che può attualmente definire. Ed è proprio in questi casi che fa una grande differenza nella qualità del codice avere un programmatore di qualità che fa delle buone domande come la tua.

    
risposta data 07.05.2016 - 21:40
fonte
0

Oltre allo scenario di iniezione delle dipendenze di Ewan.

Se si utilizza il modello di interfaccia separata -

The pattern prescribes that you use different packages for the interface and any of its implementations. Only the definition of the interface is known to any packages that need to consume the functionality.

in tale situazione il cliente / consumatore non avrà affatto il riferimento della concreta implementazione.

    
risposta data 08.05.2016 - 08:14
fonte

Leggi altre domande sui tag