Quanta logica può essere inserita in un comando? O in modo diverso: che tipo di logica è il modello di comando?

8

Utilizzo lo schema di comando da un po 'di tempo ma non sono mai veramente sicuro di quanta logica posso effettivamente inserire nel metodo Execute .

La mia attuale implementazione del modello di comando è simile a questa:

public abstract class Command
{
    public static event EventHandler Completed = delegate { };        

    public bool Success { get; private set; }

    public Exception Exception {get; private set; }

    public abstract bool Execute();

    protected bool OnCompleted(bool success, Exception ex = null)
    {       
        Success = success;
        Exception = ex;
        Completed(this, EventArgs.Empty)
        return success;
    }
}

e queste sono le domande che mi pongo (e pratico nei miei comandi):

  1. È OK mostrare caselle di messaggistica o aprire finestre di dialogo ecc.?
  2. Va bene impostare proprietà di qualsiasi oggetto?
  3. Un comando può contenere la logica aziendale?
  4. Può un comando modificare i controlli della GUI in ogni caso?
  5. A quale livello appartengono i comandi? Visualizza o livello dati? Posso avere comandi in entrambi i livelli?
  6. Un comando può fare tutto ciò che prima era button1_Click ?
  7. Dovrebbe un comando per unità testabile?
  8. Un comando può essere visto come un utente che fa uso delle API e che costruisce l'ultimo livello di un'applicazione e anche l'ultima risorsa per catturare le eccezioni?
  9. I comandi possono essere eseguiti anche tramite codice (il comando chiama api, api esegue e infine qualche altro api chiama un comando) oppure può solo l'utente invocarlo e le API non devono sapere dell'esistenza?
  10. Esiste un posto per i comandi in MVC o MVVC o in qualsiasi altro modello di progettazione con un controller? Sembrano escludersi a vicenda. Cosa è preferibile?

Ci sono molti tutorial che mostrano come implementare il pattern di comando, ma nessuno in realtà discute su come applicarlo in una vera e propria applicazione wold.

    
posta t3chb0t 21.01.2015 - 12:28
fonte

2 risposte

7

Modello di comando viene generalmente utilizzato per separare WHAT dall'OMS e WHAT da WHEN. Questo è il vantaggio di avere una semplice interfaccia semplice come:

public abstract class Command {
    public abstract void execute();
}

Immagina di avere una classe EngineOnCommand . È possibile passare questo comando ad altri oggetti che accettano istanze di comando. Questo significa che la classe che riceve questo EngineOnCommand, potrebbe anche ricevere un comando diverso da eseguirlo e non dovrebbe mai saperlo. Ciò significa che hai disaccoppiato COSA da WHO .

Ora, il secondo caso per il Command Patterm è di disaccoppiare CHE COSA da WHEN . Immaginiamo di voler creare un sistema in cui le azioni nel Database debbano essere eseguite solo di notte, ma seguendo la sequenza in cui sono state richieste. Con una coda di comandi in cui è possibile eseguire uno per uno, è possibile averlo raggiunto. L'idea è che l'invocazione del comando in realtà attiva solo un accodamento del comando su una lista da eseguire successivamente.

Spero che i miei esempi sopra aiutino a capire qual è l'idea del modello. Ora proverò a rispondere ad alcune delle tue domande usando come base.

Can a command contain business logic?

Sì, credo che dovrebbe contenerlo. Lo conterrà in un modo disaccoppiato di WHO e WHEN.

Can a command modify GUI controls in anyway?

Questo significa che lo stai accoppiando alla GUI. Ciò significa che non viene utilizzato per l'intento di disaccoppiare COSA dall'OMS. Il comando idealmente non dovrebbe sapere chi lo sta invocando, se è GUI o una funzionalità batch.

Should a command by unit-testable?

Non dovrebbe, deve essere unità testabile . Tutto il codice dovrebbe essere unità testabile, ma idealmente tutti i comandi devono essere testabili dall'unità.

Ci scusiamo per non aver risposto a tutte le tue domande, ma credo che dovresti controllare il libro GOF . Contiene alcuni buoni esempi.

    
risposta data 21.01.2015 - 14:38
fonte
2

La maggior parte dei vantaggi dei comandi è che consentono di annullare facilmente un'azione, ripetere un'azione, eseguire un'azione in più punti (tramite una connessione di rete) o eseguirla in un secondo momento, e così via.

Con questo in mente:

  1. Probabilmente no. È difficile immaginare qualsiasi situazione in cui "annullare" una finestra di dialogo ha senso, e questo è il tipo di cosa che preferirei inserire nel codice dell'interfaccia utente.

  2. Finché quell'oggetto è accessibile da qualsiasi parte che potrebbe voler eseguire il comando, ovviamente è bene cambiarne le proprietà.

  3. Assolutamente. Questo si lega al fatto che il tuo modello debba "contenere" la logica di business; in realtà è considerato un anti-modello ("modello di dominio anemico") per avere troppo poca logica di business.

  4. Se i controlli della GUI fanno parte del tuo modello, assolutamente. In caso contrario, è discutibile.

  5. Sicuramente non la vista. La vista dovrebbe essere informata che i dati o il modello sono cambiati e reagiscono di conseguenza, ma la modifica effettiva dovrebbe avvenire nei dati o nel modello.

  6. In linea di principio, probabilmente sì. Essere in grado di annullare i comandi è una delle cose migliori del modello.

  7. La funzione execute () del comando dovrebbe essere definitivamente testata dall'unità. Di nuovo, se i comandi sono legati ad un modello di qualche tipo, sono tra le parti più facili da testare per un'applicazione.

  8. Non sono abbastanza sicuro di cosa intendi, ma:

    • È perfettamente corretto per un'API esterna utilizzare i comandi come input o output. Supponendo che tu li convalidi, ovviamente.
    • "last layer" mi sembra una vista. In MVC, i comandi probabilmente dovrebbero essere generati dal controller e gestiti dal modello, quindi sarebbe sensato dire che la vista è costruita "sopra" il comando, se è quello che volevi.
    • Per quanto riguarda le eccezioni, probabilmente no. In MVC, mi aspetterei che il controller fosse l'unica ad attirare le eccezioni e trasformarle nel giusto tipo di finestra di dialogo. Non il modello / i comandi.
  9. Assolutamente. La maggior parte dei vantaggi dei comandi sono impossibili da implementare se il codice non li esegue mai.

  10. Probabilmente è ovvio, ma non li vedo come se si escludessero a vicenda. Sul mio team al lavoro, il controller traduce gli eventi generati dagli utenti in comandi, il modello riceve ed esegue i comandi (e salva i comandi "annulla" da qualche parte), e quando è fatto il controller dice alla vista di aggiornarsi in base al nuovo modello . I comandi vengono anche inviati tramite la rete a tutte le copie del modello visualizzate dagli altri utenti, quindi anche loro lo vedono. Funziona brillantemente.

E la domanda del titolo: quanta logica inserire in un comando? Non metterei alcun minimo o massimo su di esso. Quello che vorrei dire è che è una buona idea implementare comandi più complessi usando una serie di comandi più semplici e comandi di refactoring allo stesso modo in cui si farebbe il refactoring.

    
risposta data 21.01.2015 - 14:27
fonte