Perché Inversion of Control è chiamato così?


98

Le parole inverto controlnon sono affatto utilizzate per definire Inversion of Control nelle definizioni che ho visto.

definizioni

Wikipedia

inversion of control (IoC) è una tecnica di programmazione, qui espressa in termini di programmazione orientata agli oggetti, in cui l'accoppiamento di oggetti è vincolato in fase di esecuzione da un oggetto assembler e in genere non è noto in fase di compilazione mediante l'analisi statica. ~ http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

L'inversione del controllo è un modello comune nella comunità Java che consente di cablare contenitori leggeri o assemblare componenti di diversi progetti in un'applicazione coerente. ~ basato su http://www.martinfowler.com/articles/injection.html (riformulato)


Allora perché Inversion of Control si chiama Inversion of Control? Quale controllo viene invertito e da cosa? C'è un modo per definire Inversion of Control usando la terminologia: invert e control ?


22
Puntelli per la persona che può spiegarlo in un inglese semplice.
Robert Harvey,

2
Se una definizione usasse la parola che stava definendo, sarebbe un fallimento di un dizionario. La logica simile si applica qui.
Izkata,

2
Vedi anche su StackOverflow: che cos'è Inversion of Control?
Izkata,

2
@Izkata, è molto comune per i dizionari definire frasi in termini di termini propri o sinonimi. vale a dire: la definizione della forza della natura usa le parole forza e natura nella sua definizione o la definizione dei termini di servizio usa le parole regole e servizio dove regole è sinonimo di termini.
Korey Hinton,

3
Preferisco usare il termine "iniezione automatizzata delle dipendenze" o ADI anziché IoC, proprio per questo motivo; Lo stesso Fowler menziona che la maggior parte dei paradigmi attuali nella programmazione hanno una sorta di "inversione di controllo", in cui quel termine è generalmente definito come "il rinvio delle determinazioni del codice da eseguire e il momento in cui dovrebbe essere eseguito su un esterno sistema di controllo, quando tali determinazioni sono tradizionalmente fatte dal programma stesso ". Tutto dall'interruzione dell'hardware alla programmazione basata su eventi alle macchine virtuali e al multitasking avviene con IoC.
KeithS

Risposte:


67

Supponiamo che tu abbia una sorta di classe "repository" e che il repository sia responsabile della consegna dei dati da un'origine dati.

Il repository potrebbe stabilire una connessione all'origine dati da solo. E se ti consentisse di passare una connessione all'origine dati tramite il costruttore del repository?

Consentendo al chiamante di fornire la connessione, è stata disaccoppiata la dipendenza della connessione all'origine dati dalla classe repository, consentendo a qualsiasi origine dati di funzionare con il repository, non solo quella specificata dal repository.

Hai invertito il controllo passando la responsabilità di creare la connessione dalla classe repository al chiamante.

Martin Fowler suggerisce di usare il termine "Iniezione di dipendenza" per descrivere questo tipo di Inversione di Controllo, poiché Inversione di Controllo come concetto può essere applicato in modo più ampio rispetto all'iniezione di dipendenze in un metodo di costruzione.


3
Questo è un esempio di iniezione di dipendenza, ma l'iniezione di dipendenza è solo un sottoinsieme dell'inversione del controllo. Ci sono altre cose totalmente estranee all'iniezione di dipendenza che praticano l'inversione del controllo.
dsw88,

1
@ mustang2009cobra: grazie. Un esempio è quello che stavo cercando, non un catalogo completo di casi in cui si verifica e il termine "Inversion of Control" è più strettamente associato a DI, non al passaggio di messaggi o ad altri concetti simili.
Robert Harvey,

È vero, l'iniezione di dipendenza è l'esempio più prevalente di IoC, quindi un esempio di DI ha più senso. Forse una piccola modifica alla tua risposta specificando che questo è un esempio DI, qual è il tipo più importante di IoC?
dsw88,

1
Questo e 'esattamente quello che stavo cercando! Molti esempi e definizioni di IoC non specificano chiaramente quale controllo viene invertito. Mi rendo conto che ci può essere di più nell'IoC oltre all'iniezione di dipendenza, ma ora qualcosa è finalmente scattato nel mio cervello. Grazie!
Korey Hinton,

79

Non credo che nessuno possa spiegarlo meglio di Martin Fowler, più in basso nell'articolo a cui ti sei collegato .

Per questa nuova generazione di container, l'inversione riguarda il modo in cui cercano un'implementazione del plug-in. Nel mio ingenuo esempio, il lister ha cercato l'implementazione del finder istanziandolo direttamente. Questo impedisce al Finder di essere un plugin. L'approccio utilizzato da questi contenitori è garantire che qualsiasi utente di un plugin segua una convenzione che consente a un modulo assemblatore separato di iniettare l'implementazione nel lister.

Come spiega nei paragrafi precedenti, questo non è esattamente lo stesso del motivo per cui ha avuto origine il termine "Inversion of Control".

Quando questi contenitori parlano di come sono così utili perché implementano "Inversion of Control", finisco perplesso. L'inversione del controllo è una caratteristica comune dei quadri, quindi dire che questi contenitori leggeri sono speciali perché usano l'inversione del controllo è come dire che la mia auto è speciale perché ha le ruote.

La domanda è: quale aspetto del controllo stanno invertendo? Quando ho incontrato per la prima volta l'inversione del controllo, era nel controllo principale di un'interfaccia utente. Le prime interfacce utente erano controllate dal programma applicativo. Avresti una sequenza di comandi come "Inserisci nome", "inserisci indirizzo"; il tuo programma guiderà i prompt e risponderà a ciascuno di essi. Con le UI grafiche (o persino basate su schermo) il framework dell'interfaccia utente conterrebbe questo ciclo principale e il tuo programma fornirà invece gestori di eventi per i vari campi sullo schermo. Il controllo principale del programma è stato invertito, spostato da te al framework.

Questo è il motivo per cui continua a coniare il termine "Iniezione delle dipendenze" per coprire questa specifica implementazione di Inversion of Control.

Di conseguenza penso che abbiamo bisogno di un nome più specifico per questo modello. Inversione del controllo è un termine troppo generico, e quindi la gente lo trova confuso. Di conseguenza, con molte discussioni con vari sostenitori dell'IoC, abbiamo optato per il nome Iniezione delle dipendenze.

Per chiarire un po ': Inversion of Control significa tutto ciò che inverte la struttura di controllo di un programma dal classico disegno procedurale.

In passato, un esempio chiave di ciò era consentire a un framework di gestire la comunicazione tra un'interfaccia utente e il codice, anziché lasciare il codice per generare direttamente l'interfaccia utente.

In tempi più recenti (quando tali framework erano praticamente dominati, quindi la domanda non era più pertinente), un esempio era quello di invertire il controllo sull'istanza degli oggetti.

Fowler, e altri, decisero che il termine Inversion of Control copriva troppe tecniche e che avevamo bisogno di un nuovo termine per l'esempio specifico di istanziazione di oggetti (Dependency Injection) ma, al momento dell'accordo, la frase "Contenitore IoC "era decollato.

Questo confonde molto l'acqua, perché un contenitore IoC è un tipo specifico di iniezione di dipendenza, ma l'iniezione di dipendenza è un tipo specifico di inversione di controllo. Questo è il motivo per cui stai ricevendo risposte così confuse, non importa dove guardi.


4
Normalmente non voto così tanto, ma questa è un'ottima risposta. 1 voto non sarà sufficiente. :(
RJD22

1
questa risposta risponde davvero a tutte le domande sulle confusioni IoC e DI.
Ali Umair,

32

Ecco i programmi di flusso di controllo "regolari" normalmente seguiti:

  • Esegui i comandi in sequenza
  • Mantenete il controllo sul flusso di controllo del programma

L'inversione del controllo "inverte" quel controllo del flusso, nel senso che lo capovolge sulla sua testa:

  • Il tuo programma non controlla più il flusso. Invece di chiamare i comandi come meglio credi , aspetti che qualcun altro ti chiami .

L'ultima riga è quella importante. Invece di chiamare qualcun altro quando ne hai voglia, qualcun altro ti chiama quando ne ha voglia.

Un esempio comune di ciò sono i framework Web come Rails. Definisci i controller, ma in realtà non decidi quando vengono chiamati. Rails li chiama quando decide che è necessario.


19
[inserire qui la battuta obbligatoria "in Soviet"]
Robert Harvey,

2
Scherzi a parte, quello che penso tu stia descrivendo è più come passare messaggi, che è stato un punto fermo di OO per decenni.
Robert Harvey,

3
@JimmyHoffa - Questo non è affatto sbagliato - vedi qui . L'inversione del controllo è un concetto più generale della creazione di dipendenze e l'iniezione di dipendenze è solo una forma di IoC.
Lee,

7
@JimmyHoffa: non sono d'accordo. Questa è una definizione corretta di Inversion of Control come la tua risposta o quella di Robert, che è esattamente la confusione descritta da Fowler quando si coniuga la frase Dependency Injection (che è ciò che entrambi chiamate IoC).
pdr,

5
Concordo con questa affermazione di @pdr: "Inversion of Control significa tutto ciò che inverte la struttura di controllo di un programma dal classico disegno procedurale". Questo è quello che sto descrivendo, ed è l'inversione generica del controllo. L'iniezione di dipendenza è un tipo di IoC, ma non è l'unica cosa che pratica l'IoC
dsw88

13

Riguarda chi controlla l'istanza delle dipendenze.

Tradizionalmente, quando una classe / metodo deve utilizzare un'altra classe (dipendenza), viene istanziata direttamente dalla classe / metodo. Controlla le sue dipendenze.

Con Inversion of Control (IoC), il chiamante ha passato la dipendenza, quindi istanzia la dipendenza. Il chiamante controlla le dipendenze.

Il controllo di dove viene istanziata una dipendenza è stato invertito - invece di essere in "bottom", dove si trova il codice che ne ha bisogno, viene istanziato in "top", dove viene chiamato il codice che ne ha bisogno.


1
Inglese non semplice. Fallire.
Robert Harvey,

2
@RobertHarvey: quanto è semplice?
Oded,

4
@RobertHarvey Huh? Questo mi sembra abbastanza chiaro ... Cosa non è chiaro? La parola "istanziazione" o "dipendenze"?
Jimmy Hoffa,

@JimmyHoffa: vedi la mia risposta, che fornisce un esempio specifico. IoC è uno di quei termini fastidiosi che tutti usano ma nessuno spiega; le persone usano i contenitori IoC in programmi che non li richiedono perché fraintendono. Detto questo, penso che questa risposta abbia avuto un paio di modifiche ninja. :)
Robert Harvey,

Questo e il post be @ dsw88 sopra sono abbastanza chiari per me. Senti, se non avessi mai sentito parlare di IoC, penserei intuitivamente "Oh, dove chi riesce a controllare qualcosa passa da una parte all'altra". Ottimo lavoro su questo!
Oliver Williams,

2

Chiamate di codice di livello generalmente superiore (ovvero controlli) codice di livello inferiore. Main () chiama function (), function () chiama libraryFunction ().

Questo può essere invertito, quindi la funzione di libreria di basso livello in basso chiama funzioni di livello superiore.

Perché dovresti farlo? Middleware. A volte vuoi controllare il livello superiore e quello inferiore, ma nel mezzo c'è molto lavoro che semplicemente non vuoi fare. Prendi l'implementazione di quicksort in C stdlib . Chiama quicksort al livello più alto. Consegnate a qsort () un puntatore a funzione per la vostra stessa funzione che implementa un comparatore su qualunque cosa vogliate. Quando viene chiamato qsort (), chiama questa funzione di confronto. qsort () controlla / chiama / guida la tua funzione di alto livello.


1

Ecco una semplice panoramica:

  1. Il controllo si riferisce a ciò che il programma fa dopo
  2. Al livello superiore, in genere ci sono due cose che controllano il controllo: l'applicazione stessa e l'utente

In passato, il controllo era di proprietà dell'applicazione prima e dell'utente secondo. Se l'applicazione avesse bisogno di qualcosa dall'utente, si fermerebbe e chiederebbe e poi passerebbe alla sua prossima attività. L'interazione dell'utente ha fornito principalmente dati anziché controllare ciò che l'applicazione ha fatto successivamente. Questo è un po 'estraneo per noi al giorno d'oggi poiché non vediamo questo tipo di comportamento molto spesso.

Se lo cambiamo e diamo all'utente il controllo primario, allora abbiamo invertito il controllo. Ciò significa che invece che l'utente aspetta che l'applicazione dia qualcosa da fare, l'applicazione rimane in attesa che l'utente gli dia qualcosa da fare. Le GUI ne sono un ottimo esempio e praticamente qualsiasi cosa con un loop di eventi ha invertito il controllo.

Si noti che il mio esempio è al livello più alto e che questo concetto di inversione del controllo può essere astratto a diversi livelli di controllo all'interno dell'applicazione (ovvero iniezione di dipendenza). Questo potrebbe essere il motivo per cui è così difficile ottenere una risposta diretta.


0

Proviamo a capirlo attraverso i due esempi.

Esempio 1

Nei giorni precedenti, le app utilizzate per generare prompt dei comandi per accettare gli input dell'utente uno dopo l'altro. Oggi, i framework dell'interfaccia utente istanziano vari elementi dell'interfaccia utente, eseguono il ciclo attraverso vari eventi di quegli elementi dell'interfaccia utente (come passaggio del mouse, clic, ecc.) E i programmi utente / principale forniscono hook (ad esempio i listener di eventi dell'interfaccia utente in Java) per l'ascolto di quegli eventi. Quindi il "controllo" del flusso dell'elemento dell'interfaccia utente principale viene spostato dal programma utente al framework dell'interfaccia utente. Nei giorni precedenti, era nel programma utente.

Esempio 2

Valuta la classe CustomerProcessorseguente:

class CustomerProcessor
{
    SqlCustRepo custRepo = new SqlCustRepo(); 
    private void processCustomers()
    {
            Customers[] custs = custRepo.getAllCusts();
    }
}

Se voglio processCustomer()essere indipendente da qualsiasi implementazione getAllCusts(), non solo da quella fornita SqlCustRepo, dovrò liberarmi della linea: SqlCustRepo custRepo = new SqlCustRepo()e sostituirla con qualcosa di più generico, in grado di accettare vari tipi di implementazione, in modo tale che processCustomers()funzionerà semplicemente per qualsiasi implementazione fornita. Il codice sopra (istanza della classe richiesta SqlCustRepodalla logica del programma principale) è un modo tradizionale e non raggiunge questo obiettivo di disaccoppiamento processCustomers()dall'implementazione di getAllCusts(). Nell'inversione del controllo, il contenitore crea un'istanza della classe di implementazione richiesta (come specificato da, diciamo configurazione xml), la inietta nella logica del programma principale che viene vincolata come da hook specificati (diciamo per @Autowiredannotazione o getBean()metodo nel framework di primavera).

Vediamo come si può fare. Considerare sotto il codice.

Config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="custRepo" class="JsonCustRepo" />
</beans>

CustRepo.java

interface ICustRepo 
{ ... }

JsonCustRepo.java

class JsonCustRepo implements CustRepo
{ ... }

App.java

class App
{
    public static void main(String[] args) 
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
        ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
    }
}

Possiamo anche avere

class GraphCustRepo implements ICustRepo { ... }   

e

<bean id="custRepo" class="GraphCustRepo">

e non avremo bisogno di cambiare App.java.

Sopra il contenitore (che è il framework di primavera) ha la responsabilità di scansionare il file xml, creare un'istanza del bean di tipo specifico e iniettarlo nel programma utente. Il programma utente non ha alcun controllo su quale classe viene istanziata.

PS: l'IoC è un concetto generico ed è realizzato in molti modi. Gli esempi sopra riportati lo ottengono mediante iniezione di dipendenza.

Riferimento: articolo di Martin Fowler .

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.