È male usare DI per iniettare parametri di costruzione in fase di runtime?

0

Queste sono due classi, la prima inietta un'istanza di tipo IEngine mentre la seconda inietta il nome del proprietario, i ticket e il motore.

Versione 1:

public class Car
{
    public Car(IEngine engine)
    {
        // do something here
    }

    public void PrintOwnerName()
    {
    }
}

Versione 2:

public class Car
{
    // owner's name, tickets history of this car, and the engine.
    public Car(string ownerName, List<string> tickets, IEngine engine)
    {
    }

    public void PrintOwnerName()
    {
    }
}

Mi stavo chiedendo se la versione 2 è un cattivo design. Se è così, perché è male?

    
posta Anonymous 08.12.2014 - 05:36
fonte

4 risposte

5

La decisione su quali parametri deve avere un costruttore è la stessa decisione che dovrebbe avere un parametro di una funzione arbitraria - dovrebbe avere esattamente i parametri necessari per creare uno specifico , idealmente facile da capire, < strong> astrazione . E se la tua astrazione di una macchina racchiude esattamente queste tre cose, la versione 2 riflette molto meglio della versione 1.

Nella prima versione, dovresti fornire il nome del proprietario e i ticket in modo diverso, probabilmente impostando tali proprietà in seguito. Ma se queste proprietà devono sempre essere fornite, è IMHO che un design migliore lo fa rispettare dai parametri del costruttore.

Una cosa di cui ti devi preoccupare è che il numero di parametri passati attraverso la funzione di costruzione non cresce fino al punto in cui il codice diventa difficile da capire. Ad esempio, quando hai molti più parametri per la tua auto come il venditore, il colore, il numero di posti, il numero di porte, la lista dei precedenti proprietari, la patente di guida necessaria per questo tipo di auto, e così via, non dovresti ovviamente passare tutti attraverso il costruttore (almeno, non uno per uno). Un approccio per gestire questo può essere per introdurre uno o più facciate di servizio . Un altro approccio potrebbe essere quello di aggiungere alcune proprietà (per cose che sono opzionali o potrebbero essere modificate in seguito, come descritto nella risposta di @ Stephen).

Per prendere una decisione che è la soluzione migliore, tuttavia, si devono considerare i parametri attuali e il loro significato, non è possibile prendere una decisione corretta solo su "numero e tipi" dei parametri. Presumo che il tuo esempio di "macchina" sia solo un segnaposto per qualcosa di diverso nel tuo programma reale, per cui la situazione potrebbe essere diversa, ma per discuterla in termini di un'auto: il nome del proprietario è tipicamente una proprietà del proprietario, non di l'auto, e l'elenco dei biglietti è AFAIK qualcosa associato al proprietario, anche. Pertanto, potresti prendere in considerazione l'introduzione di una classe Owner per questo esempio, in cui il proprietario ha un nome e un elenco di ticket. Quindi questo porta a un costruttore

 public Car(Owner owner, IEngine engine)

Tuttavia, tenendo conto del parere di Stephen, supponendo che il proprietario di un'automobile possa cambiare durante la vita di un oggetto auto, potrebbe essere davvero meglio attenersi alla versione originale 1, fornire un getter e un setter per il "corrente" proprietario "e implementa la tua funzione PrintOwnerName() per quanto riguarda il fatto che il proprietario dell'auto potrebbe essere" sconosciuto "(che significa non inizializzato).

    
risposta data 08.12.2014 - 07:41
fonte
4

Se una proprietà soddisfa i seguenti criteri, la rendo un parametro costruttore:

  • La classe dipende da essa per l'operazione
  • Non ha motivo di cambiare durante la vita dell'oggetto
  • Il suo valore è noto alla creazione dell'oggetto

Se soddisfa questi criteri, allora è un parametro costruttore. Se soddisfa solo uno o due criteri, è quasi certamente una proprietà impostabile.

I parametri del costruttore dovrebbero essere usati per iniettare le dipendenze dell'oggetto. Usali per quello e guadagna.

    
risposta data 08.12.2014 - 07:43
fonte
1

IMHO, dipende dai parametri. Ho usato DI per iniettare preoccupazioni trasversali, come la registrazione e la gestione delle sessioni. Penso che questo sia un buon uso di DI poiché la magia di DI non influenza la logica specifica della classe.

L'iniezione di parametri specifici dell'istanza sembra richiedere problemi. Non ultimo, qualcun altro sta cercando di capire come funziona il tuo programma. A volte scrivi un po 'di codice in più per rendere il programma più semplice e comprensibile.

    
risposta data 08.12.2014 - 05:54
fonte
0

La versione 1 è migliore della versione 2. Il motivo è che una macchina non dovrebbe sapere nulla su owner o ticket s. Poiché le auto sono oggetti nel nostro mondo reale, pensaci:

Può esistere un'automobile senza avere un proprietario o biglietti? - Certamente sì .

Pertanto, rimuovi quelli da car e rendi car una classe indipendente che dipende solo da ciò che dipende dal nostro mondo: un motore e possibilmente altre proprietà tecniche.

Quindi, pensa a cosa determina il proprietario di un'auto. Quello sarebbe normalmente un servizio governativo che ha una mappa per assegnare un proprietario a un'auto. Lo stesso vale per i biglietti. Puoi andare ancora oltre e dire che non dipende nemmeno da quella macchina stessa, ma piuttosto dalla licenza che il governo ha dato alla combinazione della macchina e del proprietario.

Ma nel tuo caso basterà una modellazione più semplice, suppongo, come se avessi un solo servizio di auto-proprietario-servizio / auto-biglietteria.

Uno dei molti vantaggi di questa modellazione è, per esempio, che puoi dare a un college la classe dell'auto in modo che possa usarlo ovunque, senza dover sapere nulla dei biglietti o di avere a che fare con i proprietari di auto. Inoltre, in un secondo momento potresti trovarti in una situazione in cui desideri che una macchina sia in grado di avere, ad esempio, più proprietari, uno per ogni paese? O forse ancora più proprietà come una lista di quelle autorizzate a guidarla? In questo caso, non è necessario cambiare la classe dell'auto per questo, ma solo il servizio menzionato. Con la tua versione 1 sei quindi violazione dello SRP.

In breve: sì, la versione 2 è un cattivo design. Vai con la prima versione (e rimuovi PrintOwnerName ).

    
risposta data 08.12.2014 - 11:29
fonte

Leggi altre domande sui tag