Elaborazione delle immagini: schema di localizzazione dei servizi e contenitore delle dipendenze

1

Come per wiki ,

A dependency is an object that can be used (as a service).

qui è il paradigma OOP che utilizza la sintassi C che indirizza 4 ruoli, mostrati di seguito.

1) interfaccia ( handlers.h )

typedef struct {
    int (*canHandle) (char *);
    int (*drawImage)(char *);
    int (*savefile)(char *);
}imageHandler;

2) Prendi una dipendenza ( gifhandler.c )

imageHandler gifhandler = {
    gif_canHandle,
    gif_drawImage,
    gif_savefile
};

3) Contenitore delle dipendenze (distribuito da config.c )

//gifhandler.c - dependency 
int _init(){
    printf(" registering gifhandler \n");
    reg_handler(&gifhandler);
    return 0;
}

//config.c
imageHandler *imagehandlers[10];
int reg_handler(imageHandler *ih){
// we need to perform checks here.
    imagehandlers[libs] = ih;
    libs++;
    return TRUE;
}
// config.c
int init_handlers(){
    .....
    soptr = dlopen(so_name,RTLD_NOW);
    ....
}

4) Client: localizzatore di servizio ( UI.C )

// UI.C
switch(choice){
        case 1:
            vdrawImage(filename);   
            break;
        case 2:
            vsavefile(filename);
            break;
}
// viml.c
int vdrawImage(char *filename){
    ...
    handleno = find_handler(filename);
    ...
    ih=imagehandlers[handleno];
    ih->drawImage(filename);    
    return FALSE;       
}
// viml.c
int vsavefile(char *newfilename ){
    ...
    handleno = find_handler(newfilename);
    ...
    ih=imagehandlers[handleno];
    ih->savefile(newfilename); 
}

1) Per aggiungere una nuova dipendenza ( libxyzhandl.so.1 ) nel contenitore Dipendenze, è sufficiente aggiungere una nuova voce in config.txt configurabile , come mostrato di seguito,

config.txt

./libgifhandl.so.1

./libtiffhandl.so.1

2) Nuovo servizio fornito da ./libxyzhandl.so.1 , sarà contenuto dal contenitore delle dipendenze senza ri-compilazione di applicazione.

3) Il test dell'applicazione completa è non richiesto , ad eccezione del codice sorgente di libxyzhandl.so .

Quindi, se config.txt diventa vuoto, l'applicazione non fa nulla, tranne il dire, We cannot handle this kind of files , mostrato qui , per qualsiasi input (file immagine).

Di seguito è la visualizzazione del flusso chiamate,

Domanda:

Questo contenitore di dipendenze può essere chiamato un contenitore IOC ?

    
posta overexchange 23.07.2017 - 09:50
fonte

4 risposte

1

Dal punto di vista del codice client che hai postato, questa è l'iniezione di dipendenza non . Il tuo cliente fa riferimento a una raccolta di oggetti definita staticamente e ne richiede uno che corrisponda a determinati criteri, che è molto più simile al schema Locator del servizio rispetto all'iniezione di dipendenza. Detto questo, sono due modelli simili che raggiungono un numero di obiettivi identici. L'unica vera differenza è che non sarebbe possibile per la tua applicazione avere, ad esempio, due diverse invocazioni di vdrawImage o vsavefile che utilizzano un diverso oggetto gestore per lo stesso tipo di file (che potrebbe essere vantaggioso per il test dell'unità , ad esempio), mentre l'iniezione tradizionale delle dipendenze ha un po 'più di overhead ma può raggiungere questo livello di configurazione.

    
risposta data 27.07.2017 - 20:26
fonte
4

Dependency injection can be used to externalize a system's configuration details into configuration files

Se stai facendo un semplice passaggio di riferimento, puoi fare la tua configurazione in main (o qualunque sia la tua radice di composizione). Questo è certamente l'iniezione di dipendenza. L'uso di un file di configurazione che non è necessario compilare per creare il grafico dell'oggetto è facoltativo.

L'obiettivo in entrambi i casi è quello di avere una chiara separazione tra codice di comportamento e codice di costruzione.

Non posso davvero dire se stai raggiungendo questo obiettivo perché non vedo dove viene costruito imageHandler . Tutto quello che so è che non sembra che reg_handler lo stia costruendo. Che se reg_handler contiene codice di comportamento, è una buona cosa.

    
risposta data 23.07.2017 - 16:38
fonte
1

Posso capire perché questa discussione va in direzioni divergenti, con persone diverse che danno risposte diverse.

Iniezione delle dipendenze descrive una tecnica in programmazione orientata agli oggetti (OOP). Nel frattempo, il tuo codice di esempio non è OOP.

L'obiettivo di Dependency Injection è quello di avere flessibilità - per consentire a un pezzo di codice client di funzionare con una scelta di diverse implementazioni del servizio, senza richiedere la ricompilazione del codice client. A tal fine, il codice di esempio non OOP sembra avere lo stesso tipo di flessibilità, anche se non è OOP.

Come notato da altri, il tuo codice contiene alcune caratteristiche del localizzatore di servizio, del sistema di plugin e della configurazione del contenitore IoC utilizzando i file di configurazione.

Tuttavia, poiché il tuo codice di esempio è non-OOP, i programmatori che si trovano in profondità in OOP non possono utilizzare le loro regole del pollice per giudicare se il tuo codice si adatta a un determinato pattern OOP.

Riguardo all'iniezione di dipendenza, i programmatori OOP porranno queste domande:

  1. Esistono diverse implementazioni del servizio? (ad esempio S1, S2, S3, ...)
  2. Queste implementazioni di servizio implementano la stessa interfaccia (I)? Oppure derivano tutti dalla stessa classe base astratta (S)?
  3. Il client (codice dell'applicazione) utilizza l'implementazione del servizio in modo strettamente conforme all'interfaccia (tramite I o S)?
  4. Il codice cliente è incapsulato in un oggetto (C)?
  5. Quando l'oggetto client (C) viene inizializzato (ad es. nel costruttore, o poco dopo essere stato costruito), consente all'utente di questo oggetto (il proprietario di C, quindi non parte di C ma ad un comando superiore livello) per specificare quale implementazione del servizio utilizzare, passando in un'istanza di tale implementazione?

La condizione # 5 è la caratteristica identificativa univoca dell'iniezione di dipendenza. Per i programmatori OOP, saliranno alla condizione # 5 senza verificare le condizioni # 1 - # 4. È perché i programmatori OOP li hanno dati per scontati. Pertanto, i programmatori OOP chiederanno di vedere il costruttore o i creatori di proprietà dell'oggetto client (C). Il tuo codice non ha questi.

Quando si applicano queste condizioni al codice di esempio, i risultati sono:

  1. Si
  2. Sì. Tuttavia, l '"interfaccia" non è basata sull'interfaccia in stile OOP o sulla classe base astratta. Invece, si basa su puntatori di funzioni in stile C.
  3. Sì.
  4. Nessun. Esiste una "applicazione" che esegue un ciclo di applicazione guidato da menu.
  5. Non applicabile. Il codice dell'applicazione è già al massimo livello di comando; non c'è altro "codice". In un certo senso, l'unico livello di comando superiore è l'utente (umano) che fornisce l'input da tastiera al programma.

Modificato: Supponiamo di estendere la definizione di OOP per coprire i puntatori di funzioni in stile C e i vtables espliciti. Ecco la mia risposta:

L'essenza di Dependency Injection è che, dopo aver ottenuto un puntatore a imagehandler , come in:

// ih is a pointer to a struct that contains three function pointers
ih = imagehandlers[handleno]; 

che hai altre funzioni che accettano il puntatore ih come parametro di funzione (argomento di input). Questa è l'essenza.

    
risposta data 28.07.2017 - 12:46
fonte
0

Mi sembra, questo è più in linea con il principio Open / Closed. L'iniezione delle dipendenze astrae le dipendenze comuni in modo che l'implementazione della dipendenza astratta non sia importante e venga "iniettata" nel processo, mediante la funzione di costruzione o l'iniezione di proprietà.

    
risposta data 23.07.2017 - 11:03
fonte