Utilizzo del modello di comando per una sequenza di attività

7

Ho una "sequenza di attività" da intraprendere su un file zip. Può essere semplificato in questi passaggi:

  1. Convalida che il file è un file ZIP ed è valido
  2. Decomprimi il file
  3. Convalidare i contenuti come previsto
  4. Trasforma il contenuto in un prodotto

Attualmente sto usando il pattern Command e sembra un po 'come questo

interface Command {
    public function execute($data);
}

class ValidateFile implements Command { 
    public function execute($filePath) { //... }
}

class UnzipFile implements Command { 
    public function execute($filePath) { //... }
}

class ValidateContents implements Command {
    public function execute($unzippedFilePath) { //... }
}

class ProductGenerator implements Command {
    public function execute($unzippedFilePath) { //... }
}

Ora, ognuno di questi comandi di esecuzione restituisce una stringa che è a sua volta (dal comando invoker) passata al comando successivo nella catena (definito dalla configurazione).

Ho due problemi qui:

  1. Ogni comando richiede le sue dipendenze, ovvero decomprimere l'accesso a ZipArchive, una classe che gestisce la decompressione dei file zip. Come faccio a iniettare le dipendenze di ciascun comando? Sono abbastanza felice di aggirare questo istanziando tutti i comandi attraverso un DIC e inserendoli in un "Invoker" che accetta oggetti istanziati di tipo Command, li esegue in sequenza, tuttavia non sembra giusto.

  2. (Altro di un problema) Come faccio a mantenere più di una stringa tra i comandi? Ho visto in luoghi persone che passano un oggetto "contesto" da un comando a un altro, tuttavia questo sembra un po 'sporco in quanto il comando dipenderebbe da un'interfaccia non tipizzata (essenzialmente avvolgono un array associativo). Ha senso che deve essere non tipizzato, come se tu dovessi mantenere un'interfaccia tra i comandi, quindi il contesto non può implementare metodi specifici che potrebbero dissuadere dalla sua astrazione.

Gradirei qualsiasi consiglio su come affrontare entrambi questi problemi.

Modifica: un altro problema che ho è che ognuno di questi comandi è in realtà accoppiato allo stato del percorso del file che è passato ad esso, sono abbastanza specifici per il caso in questione, ma dubito che sia possibile lavorare oltre quello .

    
posta Matthew Haworth 05.09.2014 - 11:41
fonte

1 risposta

5

Alla tua prima domanda: è abbastanza normale che ogni costruttore di comandi possa avere una firma diversa con dipendenze diverse, quindi la costruzione dei comandi non può essere eseguita completamente generica. L'utilizzo di un DIC può effettivamente mitigarlo.

Per scenari più complessi, puoi anche utilizzare il pattern "factory astratta", in cui hai una classe factory per comando, tutti derivati da un'interfaccia factory astratta e ogni factory che incapsula le attività specifiche per la creazione del singolo comando . Queste fabbriche possono quindi essere passate a un generico "FactoryInvoker". Ma dovresti pensarci due volte se vale veramente la spesa aggiuntiva in codice.

Alla tua seconda domanda: passare un oggetto "contesto" da un comando a un altro va bene. Le soluzioni generiche a volte arrivano per il prezzo della riduzione di alcuni tipi di sicurezza. Se pensate di aver davvero bisogno di tanta sicurezza, fate del "contesto" una classe base astratta, con sottoclassi diverse che rappresentano ognuna un diverso tipo di contesto. Ma attenzione, questo può facilmente portare a una soluzione totalmente sovrastampata e non flessibile, che può causare un sacco di sforzo quando devi cambiare il flusso di comandi in seguito.

    
risposta data 05.09.2014 - 13:29
fonte

Leggi altre domande sui tag