Iniezione delle dipendenze: devo creare una classe Car per contenere tutte le sue parti?


10

Ho molte macchine nella mia applicazione C ++ tutte contenute in RaceTrack.

Ogni auto è composta da centinaia di parti. Ogni parte dipende da qualche altra parte o due.

Ho letto molte domande SO sul libro di DI e Mark Seemann e sembra che non dovrei definire una classe di auto solo per contenere parti di automobili perché tutte le parti di automobili dipenderanno l'una dall'altra e questa zuppa di parti è un'auto. Ho ragione?

Quindi, quando inserisco tutte le mie auto da corsa nella RaceTrack non ci saranno entità auto ma molte parti di auto che dipendono l'una dall'altra in pista ?? Ho ragione?

MODIFICARE:

Per anni ho programmato le classi di auto perché era ovvio per me che avevo bisogno di una classe di auto se sto programmando una logica di auto. Ma con DI non è così ovvio per me. Ti stai ancora chiedendo se è un idiomatico per DI non creare una classe Car se non ho un ruolo definito per esso?

Voglio dire, va bene avere uno SteeringWheel per la guida, BoltsAndNuts su ruote per il personale di bordo e tutti i tipi di altre interfacce divertenti senza avere un'istanza che rappresenti un'auto nel suo insieme?

Risposte:


24

A che serve un gruppo di parti di automobili seduti su una pista che fanno qualcuno?

Se tutta la tua classe di auto fa è tenere le parti dell'auto è utile come un sacchetto bagnato di parti.

uso

Come pilota, quello che voglio è qualcosa che posso controllare. Ciò risponde quando chiedo velocità. Che gestisce come sui binari. Questo può fermarsi in un centesimo.

Quello che voglio è una classe di auto utilizzabile. Che posso dire di fare le cose senza dover pensare a come funziona il carburatore. Penso solo al pedale dell'acceleratore. Il modo in cui sono collegati non è qualcosa di cui mi preoccupo. Questa è astrazione.

Iniezione di dipendenza

L'iniezione di dipendenza non ha nulla a che fare con questo. Quando guido la macchina non penso a come è stata costruita. Finché funziona, non mi interessa come lo mettono insieme.

No, DI è ciò che consente al mio team di addetti ai lavori di sostituire rapidamente le mie gomme con pneumatici migliori quando inizia a piovere in pista. È bello poterlo fare senza dover salire su un'auto completamente diversa.

DI si basa sul seguire un principio: separare l'uso dalla costruzione.

Un'auto in grado di installare pneumatici nuovi a 90 miglia all'ora potrebbe sembrare interessante, ma non credo che vincerà alcuna gara con un pneumatico che installa un aggeggio su di esso.

DI consiste nell'installare le tue parti in modo tale da consentire al tuo team di addetti ai lavori di raggiungerle. Quando si usa newnello stesso posto in cui si programma il comportamento è come se si stesse saldando il carburatore in posizione. Sicuramente una torcia in acetilene potrebbe rimuoverla, ma per favore considera di usare prima dadi e bulloni.

Questo è DI. Certo non è facile come newinventare qualcosa non appena ti rendi conto di volerlo. Invece devi scrivere un codice separato che sappia come costruire la tua auto. Ma sicuramente rende più facile cambiare le cose in seguito. E significa che non devi trascinare con te un impianto di assemblaggio di auto lungo la pista.

Costruzione

Qualcosa, da qualche parte, deve sapere se le gomme sono Goodyear. Dove quindi inserire il codice di costruzione dell'auto? Se non la macchina, allora l'equipaggio dei box? No. La traccia? No. Tutti quelli hanno un codice di comportamento. Codice che deve essere eseguito durante la gara. La costruzione dell'auto dovrebbe avvenire prima della gara in un posto rimosso dal codice di comportamento. Mark Seemans ha chiamato questo posto il Root di composizione . Molte persone lo chiamano principale.

È un modello semplice. In linea di principio, costruisci il grafico a oggetti, quindi chiama un metodo comportamentale su un oggetto nel grafico a oggetti. Questo è tutto. Questo è l' UNICO posto in cui costruzione e comportamento devono stare insieme.

Ciò non significa che la costruzione debba essere un mucchio di codice procedurale, tutti disposti in sequenza in linea di principio. Sei libero di usare tutti gli strumenti nella lingua per fare la costruzione. Basta non mescolarlo con il comportamento.

Fare questo nella lingua e non usare alcun framework DI o contenitore IoC è chiamato DI puro . Funziona molto bene È da molto tempo. Lo chiamavamo solo riferimento di passaggio .

Strumenti DI

Ciò che uno strumento DI ti compra sono i dettagli di costruzione spostati in una lingua diversa (xml, json, qualunque cosa) che impone la separazione tra costruzione e comportamento. Se non ti fidi dei tuoi colleghi programmatori di non usare newquando non dovrebbero, può essere attraente.

L'inconveniente è che è allettante lasciare che i dettagli dello strumento DI si diffondano in tutta la base di codice. A volte infetta la base di codice con annotazioni proprietarie. Gli esempi che forniscono certamente incoraggiano questo. Lo strumento tende a spostarsi nello spazio linguistico fino a quando non è possibile pubblicizzare il lavoro solo come lavoro di programmazione Java ma come lavoro di programmazione Java / Spring.

Principi di progettazione

Per anni ho programmato le classi di auto perché era ovvio per me che avevo bisogno di una classe di auto se sto programmando una logica di auto. Ma con DI non è così ovvio per me. Ti stai ancora chiedendo se è un idiomatico per DI non creare una classe Car se non ho un ruolo definito per esso?

Penso che stai imparando l'astrazione e cambiando il modo in cui decidi che una lezione è necessaria. Quello è buono. Ma non si tratta di DI. DI non ti aiuta a decidere se hai bisogno di una classe di auto. DI ti aiuta a impedire alla macchina di sapere, e quindi a prendersi cura, se i pneumatici sono pneumatici Goodyear. DI ti aiuta a non sapere se le macchine sono prodotte in Giappone.

Una delle domande più fondamentali nella progettazione del software è "cosa sa di cosa?" Questa è la cosa principale che ti mostra un diagramma UML. Quando rinnovi qualcosa che stai raggiungendo, è l'interfaccia con la cosa concreta a cui sei ora legato. L'auto ora deve sapere che le gomme sono Goodyear. Che tipo di schifo se la Michelin vuole sponsorizzarti.

Evitare di farlo si chiama seguendo il principio di inversione di dipendenza . Formalmente, un modulo di alto livello (come la classe auto) non dovrebbe dipendere direttamente da moduli di basso livello (come la classe GoodyearTire). Dovrebbe dipendere da un'astrazione (come un'interfaccia di Tyre).

Un modo per evitare di farlo è chiamato Inversion of control . Qui l'accento è posto sulla modifica del flusso di controllo. Le gomme muovono l'auto o l'auto muove le gomme? Pensare a questo nel modo giusto ci consente di non accoppiare staticamente auto e pneumatici. DI è un modo particolare per seguire Inversion of Control.

Niente di tutto ciò ti dice se hai bisogno di una classe di auto. Se stai programmando la "logica dell'auto" è bello se c'è un posto dove tenerlo piuttosto che spargerlo ovunque. Non farti ingannare nel pensare che la logica di costruzione dell'auto sia la stessa della logica di comportamento dell'auto, quindi tutto deve vivere nello stesso posto. Ma se non hai un tiro definito per un'auto, non hai nemmeno bisogno. Fai correre le motociclette intorno alla pista, se lo desideri.

Voglio dire, va bene avere uno SteeringWheel per la guida, BoltsAndNuts su ruote per il personale di bordo e tutti i tipi di altre interfacce divertenti senza avere un'istanza che rappresenti un'auto nel suo insieme?

DI o no DI, va bene avere un'istanza che rappresenta un'auto nel suo insieme, ma quell'istanza non è qualcosa che voglio sapere direttamente se non devo. Dammi un'astrazione in auto, quindi non devo preoccuparmi se funziona a gas, diesel o elettricità quando lo uso. È solo qualcosa di cui dovrei preoccuparmi quando lo costruisco o lo mangio. È bello se il codice che utilizza l'auto non deve sapere o preoccuparsi di come funziona. "Non lo so. Non voglio saperlo."


Sarebbe bello se non usassi la metafora della macchina e dell'equipaggio per una domanda che li usa per rappresentare il codice. Ma comunque, una buona risposta.
S. Tarık Çetin,

6
E ho sempre pensato che Inversion of Control fosse quando si sterzava a sinistra, ma l'auto gira a destra ...
mkrieger1

CandiedOrange, quindi nessuna classe Car se non ha un'interfaccia significativa e responsabilità ben definite? E niente Car.h nel mio progetto. E un collega che esamina il mio codice e si chiede se si tratti di un negozio online di ricambi per auto o di un garage? :)
Anton Petrov,

@AntonPetrov "se sembra un'anatra e cigola come un'anatra, ma ha bisogno di batterie probabilmente hai l'astrazione sbagliata". I buoni nomi sono molto importanti e possono essere difficili da pensare ma dovrebbero essere cambiati per riflettere la responsabilità ben definita e l'interfaccia significativa in modo da non essere una sorpresa. Se leggo il nome allora guardo l'interfaccia e penso "è praticamente quello che mi aspettavo", allora hai un buon nome.
candied_orange

15

sembra che non dovrei definire una classe di auto solo per contenere parti di automobili perché tutte le parti di automobili dipenderanno l'una dall'altra e questa zuppa di parti è un'auto. Ho ragione?

No.

Il punto dell'iniezione di dipendenza non è affatto quello di scoraggiare le dipendenze. Piuttosto il contrario.

Iniezione di dipendenza è di circa la domanda: da dove viene la macchina ottiene le sue parti da ? Dove e come vengono creati e in che modo l'auto ottiene riferimenti ad essi?

Ingenuamente, l'auto avrebbe creato le sue parti stesse chiamando new. Questo è facile e diretto, ma è molto poco flessibile. L'auto deve sapere tutto ciò che è necessario per creare le parti, e se mai vuoi avere due auto con parti diverse, anche quella logica deve entrare nell'auto.

Con l'iniezione delle dipendenze, tutta quella logica viene estratta dall'auto e inserita in un componente di configurazione, che crea tutte le parti e collega i riferimenti. Le dipendenze completamente configurate vengono iniettate nell'auto e l'una nell'altra.


1
Finalmente una spiegazione sana del dependency injectionconcetto.
Anatoly Techtonik,

1
Direi che il sistema più comune per l'approccio "ingenuo" non è che la macchina chiamerebbe nuova, ma che l'utente della classe automobilistica assegnerebbe le sue parti alle sue proprietà, e nel frattempo la classe automobilistica sarebbe in uno stato indeterminato. DI fornisce un mezzo per assicurare meccanicamente la validità della classe.
whatsisname

2
@whatsisname Posso facilmente usare DI per rendere gli oggetti non inizializzati e mezzo inizializzati. La convalida non è una responsabilità DI. Né è immutabile. DI può assumere il compito di costruire oggetti validi e immutabili. DI non ha modo di imporre che quelli siano gli unici modi in cui tali oggetti sono costruiti e usati. Gli oggetti devono imporre questo.
candied_orange

@CandiedOrange: così puoi facilmente usare qualsiasi tecnica per fare qualcosa per metà, e allora? Richiedere dipendenze dal costruttore e renderle immutabili, non è un proiettile d'argento, ma è comunque un modo molto utile per prevenire molte brutte situazioni comuni.
whatsisname

0

Quindi, quando inserisco tutte le mie auto da corsa nella RaceTrack non ci saranno entità auto ma molte parti di auto che dipendono l'una dall'altra in pista ?? Ho ragione?

Bene. Sì e no. Un'entità auto è ancora valida per avere. E un'auto è più della somma delle sue parti. Anche tu hai bisogno di un autista (per il momento). Molte volte anche le auto da corsa hanno nomi, per non parlare della marca e del modello dell'auto.

Sì, le auto sono fondamentalmente un contenitore di parti, ma è proprio l'imballaggio e la collaborazione delle parti che compongono qualcosa di più grande: un'auto.

Quindi davvero, no. Un'auto non è solo una borsa a caso di metallo e plastica. È una macchina

In questo caso l'iniezione di dipendenza non è eccessiva. Qualcos'altro deve costruire l'auto, che sarebbe una classe di fabbrica o un oggetto Builder. L'auto non dovrebbe sapere come costruirsi.


2
Puoi avere DI senza fabbriche o oggetti costruttore. I semplici parametri del costruttore sono un metodo valido che funziona in molte circostanze.
whatsisname
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.