Devo seguire la regola del "principio di inversione di dipendenza" anche se ho bisogno di un solo tipo e non ho bisogno di polimorfismo?

0

Considera che ho delle lezioni come segue:

public class User{
    private String name;
    //other code
    private String getName(){
        return name;
    }
}

public class ShowUserInfo{
    public void show(User user){
        System.out.println(user.getName());
    }
}

Sono abbastanza sicuro che non avrei altre varianti dell'utente e non richiede il polimorfismo per l'utente. Ma sta violando la regola del "principio di inversione di dipendenza": ShowUserInfo dipende dall'utente di classe concreto, anziché dalle astrazioni. La mia domanda è, dovrei creare l'interfaccia per l'utente:

public interface User{
    String getName();
}

public class UserImp implements User{
    private String name;
    //other code
    @Override
    private String getName(){
        return name;
    }
}

anche se non ho bisogno di polimorfismo e abbastanza sicuro che avrebbe un solo tipo di Utente solo?

    
posta mmmaaa 29.11.2017 - 02:37
fonte

5 risposte

4

Sì, ma solo se ne hai bisogno.

Il principio di inversione delle dipendenze non significa far funzionare qualcosa ora. Parla di astrazioni e concrezioni, ma non si tratta proprio di questo.

Riguarda il cambiamento.

Posso far funzionare qualsiasi cosa senza DIP. Seriamente, non esiste un singolo programma che non possa essere scritto completamente senza DIP.

Non usiamo il DIP per soddisfare un requisito. Usiamo il DIP in modo che l'inevitabile nuovo requisito non imponga una riscrittura, ricompilazione e ridistribuzione massiva.

Quindi, hai bisogno DIP qui?

Bene, non c'è molto codice qui da seguire, a parte che è chiaro che ShowUserInfo conosce User . La domanda quindi è se ci interessa.

Pensa a questo: User conosce String . String è concreto come viene. Eppure nessuno getta mai DIP a String . Perché? Perché String è stabile (improbabile che cambi). Puoi dire la stessa cosa su User ?

Se User è volatile (probabilmente modificabile), allora è pericoloso per ShowUserInfo sapere direttamente. Una modifica a User richiede una modifica a ShowUserInfo se non c'è DIP. Un'interfaccia più stabile o una classe puramente astratta (non importa quale) aiuta a proteggere da questa volatilità.

Ora serve solo un'astrazione più stabile. DIP può effettivamente fare un po 'di più per te.

DIP consente al flusso di controllo di andare contro la dipendenza del codice sorgente. Ciò ti offre ancora più opzioni per isolare dai cambiamenti.

Di User e DisplayUserInfo che pensi sia più stabile?

Il solito schema prevede che le classi di regole aziendali siano le più stabili e le classi di reporting / adattamento che comunicano con il mondo esterno lo siano meno. Ma, se per qualche motivo pensavi che User fosse meno stabile, potresti usare DIP per invertire la dipendenza del codice sorgente in modo che DisplayUserInfo non sappia nulla su User e quindi sia protetto dalla sua volatilità. È meglio conoscere le cose stabili delle cose instabili. Ciò che non sai non ti può ferire.

Questa è la vera cosa bella di quelle frecce aperte < | - vedi nei diagrammi UML. Il flusso del controllo li attraversa all'indietro. Questa inversione di direzione è dove questo principio prende il nome.

Poiché DIP ti consente di sostituire una freccia usa - > con una freccia di attrezzi < | - puntando dall'altra parte, si arriva a decidere cosa sa di cosa indipendentemente da ciò che deve parlare a cosa. Questo è il vero potere di DIP.

    
risposta data 29.11.2017 - 05:04
fonte
6

Il principio di inversione delle dipendenze non è un metodo per usare le interfacce, né è principalmente sull'abilitazione del polimorfismo.

DI riguarda circa fornire dipendenze a una classe dall'esterno, piuttosto che avere quella classe crea le sue dipendenze. Ciò consente alla classe di non essere vincolata a una determinata implementazione. Invece, puoi fornire l'implementazione che desideri venga utilizzata dalla classe, e tutta la classe è a conoscenza dell'interfaccia.

Pensa alle interfacce come alla creazione di un contratto, in modo che una implementazione possa venire avanti e soddisfare quel contratto:

public interface Dancer
{
    public void dance();
}

public class SalsaDancer implements Dancer
{
    public void dance()
    {
        // Do the salsa.
    }
}

public class ChaChaDancer implements Dancer
{
    public void dance()
    {
        // Do the Cha Cha.
    }
}

public class User implements Dancer
{
    private Dancer _dancer;

    public User(Dancer dancer)
    {
         _dancer = dancer;
    }

    public void dance()
    {
        _dancer.dance();
    }
}

public static void main()
{
    dancer d = new SalsaDancer();
    User u = new User(d);
    u.dance();  // does the salsa.
}

Ora, naturalmente, forse sosterrai solo un SalsaDancer. Il polimorfismo non è l'unica ragione per cui potresti voler fornire DI. Potresti anche voler dare alla classe la capacità di essere deriso, in modo che possa essere testato indipendentemente dall'implementazione di un Dancer.

    
risposta data 29.11.2017 - 03:12
fonte
2

Nel tuo esempio User sembra un modello anemico . Un modello anemico è puramente di dati e non di logica. Non è necessario definire un'interfaccia per questi modelli perché:

  • Esiste un solo modo per scrivere un modello anemico di dati per un determinato set di campi, quindi non c'è alcun vantaggio nel consentire di scambiare implementazioni definendo un'interfaccia.
  • In un modello di progettazione anemico, il tuo codice formula ipotesi basate sulla consapevolezza che il modello è anemico. Per esempio. se hai definito getName() per restituire una stringa casuale a ogni invocazione, si interromperanno tali ipotesi.

Se il tuo modello contiene qualsiasi logica aziendale non è più anemico e potresti voler inserire un'interfaccia. Per es.

public class User{
    private String firstName;
    private String lastName;

    public String getDisplayName(){
        // Business logic!!!!
        return String.format("%s %s", firstName, lastName);
    }
}

Dovresti creare un'interfaccia qui perché non puoi unire gli utenti di test di getDisplayName senza abbinare il test all'implementazione di getDisplayName . Inoltre è necessario testare

    
risposta data 29.11.2017 - 03:15
fonte
0

Non hai bisogno di un'interfaccia da cui l'utente possa derivare. L'utente è effettivamente vecchi dati. Tuttavia, dovresti avere un'interfaccia per la tua classe ShowUserInfo perché fornisce un effetto collaterale che dovrai testare per assicurarti che venga chiamato al momento giusto. In altre parole, alcune classi usano ShowUserInfo e devi essere in grado di sostituirle con una versione di prova.

    
risposta data 29.11.2017 - 03:19
fonte
-3

Il principio "Iniezione di dipendenza" è puro design di culto del carico. Se hai bisogno di un'iniezione di dipendenza, hai una situazione che non può essere risolta in altro modo: per esempio, il codice di terze parti deve essere iniettato in un'applicazione precedentemente costruita. Ogni altro uso dell'iniezione di dipendenza sta semplicemente seguendo una moda popolare. Non esiste un tale "principio", ma se credi che ci sia, puoi unirti ai ranghi di molti sviluppatori che sprecano i loro fondi dei datori di lavoro creando una complessità inutile.

    
risposta data 01.12.2017 - 19:21
fonte

Leggi altre domande sui tag