Utilizzo di un modello di strategia e di un modello di comando


121

Entrambi i modelli di progettazione incapsulano un algoritmo e separano i dettagli di implementazione dalle rispettive classi chiamanti. L'unica differenza che posso distinguere è che il pattern Strategy accetta i parametri per l'esecuzione, mentre il pattern Command no.

Mi sembra che il modello di comando richieda che tutte le informazioni per l'esecuzione siano disponibili quando viene creato, ed è in grado di ritardare la sua chiamata (forse come parte di uno script).

Quali determinazioni guidano se usare uno schema o l'altro?

Risposte:


94

Includo una tabella della gerarchia di incapsulamento di diversi modelli di progettazione GoF per spiegare le differenze tra questi due modelli. Spero che illustri meglio ciò che ciascuno racchiude in modo che la mia spiegazione abbia più senso.

Prima di tutto, la gerarchia elenca l'ambito per il quale un determinato modello è applicabile o il modello appropriato da utilizzare per incapsulare un certo livello di dettaglio, a seconda del lato della tabella da cui si inizia.

tabella gerarchica di incapsulamento del modello di progettazione

Come puoi vedere dalla tabella, un oggetto Pattern di strategia nasconde i dettagli dell'implementazione di un algoritmo, quindi l'uso di un oggetto di strategia diverso eseguirà la stessa funzionalità ma in modo diverso. Ogni oggetto strategia potrebbe essere ottimizzato per un particolare fattore o operare su qualche altro parametro; e, attraverso l'uso di un'interfaccia comune, il contesto può funzionare in sicurezza con entrambi.

Il modello di comando incapsula un livello di dettaglio molto inferiore rispetto a un algoritmo. Codifica i dettagli necessari per inviare un messaggio a un oggetto: ricevitore, selettore e argomenti. Il vantaggio di oggettivare una parte così piccola dell'esecuzione del processo è che tali messaggi possono essere invocati in diversi momenti o in un luogo in modo generale senza dover codificare i suoi dettagli. Consente ai messaggi di essere invocati una o più volte o passati a parti diverse del sistema o più sistemi senza richiedere che i dettagli di una chiamata specifica siano noti prima dell'esecuzione.

Come è tipico dei design pattern, non richiedono che tutte le implementazioni siano identiche nei dettagli per portare il nome del pattern. I dettagli possono variare nell'implementazione e in quali dati sono codificati nell'oggetto rispetto agli argomenti del metodo.


Quindi, se avessi un sistema che filtra i risultati con una "pipeline di filtri" e utilizza i delegati come filtri (dove ciascuno degli algoritmi del filtro sarebbe incapsulato all'interno di una funzione) sarebbe considerato un modello di comando? In questo caso, vedo il delegato per la funzione di filtro che fornisce una sorta di contratto per ciò a cui ogni filtro deve aderire in termini di input e output.
KTF

4
@KTF, no. Il pattern Command utilizza un oggetto che ha la maggior parte (se non tutte) le informazioni necessarie (ad esempio, ricevitore, selettore, argomenti) per invocare il metodo di un oggetto. È un modello semplicistico che può essere utilizzato in altri modelli di progettazione come Catena di responsabilità, Raccolta e il modello Pipeline che descrivi. Il "contratto di sorta" fornito dai vostri delegati è un altro modello, Interface.
Huperniketes

50

Le strategie incapsulano algoritmi. I comandi separano il mittente dal destinatario di una richiesta, trasformano una richiesta in un oggetto.

Se si tratta di un algoritmo, come verrà fatto qualcosa, usa una strategia. Se è necessario separare la chiamata di un metodo dalla sua esecuzione, utilizzare Command. I comandi vengono spesso utilizzati quando si accodano i messaggi per un uso successivo, come un'attività o una transazione.


che aveva senso en.wikipedia.org/wiki/Command_Pattern client e invoker sono legati, ma allo stesso tempo non si conoscono!
Kalpesh Soni

26

Rispondendo a una domanda molto vecchia. (qualcuno vede le risposte più recenti invece di quelle più votate?)

È una valida confusione da avere a causa delle somiglianze. Entrambi i modelli di strategia e comando utilizzano l' incapsulamento . Ma questo non li rende uguali.

La differenza fondamentale è capire cosa è incapsulato. Il principio OO, da cui dipendono entrambi i modelli, è Incapsula ciò che varia .

In caso di strategia, ciò che varia è l' algoritmo . Ad esempio, un oggetto strategia sa come eseguire l'output in un file XML, mentre l'altro output, ad esempio, JSON. Diversi algoritmi sono conservati ( incapsulati ) in classi differenti. È così semplice.

In caso di comando, ciò che varia è la richiesta stessa. La richiesta può provenire da File Menu > Deleteo Right Click > Context Menu > Deleteo Just Delete Button pressed. Tutti e tre i casi possono generare 3 oggetti comando dello stesso tipo. Questi oggetti comando rappresentano solo 3 richieste di cancellazione; non l'algoritmo di cancellazione. Poiché le richieste ora sono un mucchio di oggetti, potremmo gestirle facilmente. All'improvviso diventa banale fornire funzionalità come annulla o ripeti.

Non importa come il comando implementa la logica richiesta. Quando si chiama execute (), può implementare un algoritmo per attivare l'eliminazione o può anche delegarlo ad altri oggetti, può anche delegare a una strategia. È solo un dettaglio di implementazione del modello di comando. Questo è il motivo per cui è chiamato comando sebbene non sia un modo educato per richiedere : -)

Confrontalo con la strategia; questo modello riguarda solo la logica effettiva che viene eseguita. Se lo facciamo, aiuta a ottenere diverse combinazioni di comportamenti con un insieme minimo di classi, prevenendo così l'esplosione di classe.

Penso che Command ci aiuti ad ampliare la nostra comprensione dell'incapsulamento mentre Strategy fornisce un uso naturale dell'incapsulamento e del polimorfismo.


15

Per come la vedo io, hai più modi per fare la stessa cosa, ognuno di questi è una strategia, e qualcosa in fase di esecuzione determina quale strategia viene eseguita.

Forse prima prova StrategyOne, se i risultati non sono abbastanza buoni, prova StrategyTwo ...

I comandi sono associati a cose distinte che devono accadere come TryToWalkAcrossTheRoomCommand. Questo comando verrà attivato ogni volta che un oggetto dovrebbe provare a camminare attraverso la stanza, ma al suo interno potrebbe provare StrategyOne e StrategyTwo per provare ad attraversare la stanza.

marchio


2
RE: "molteplici modi di fare la stessa cosa" - Questo sembra essere in conflitto con alcuni degli esempi comuni di strategia. In particolare quelli in cui ci sono classi di implementazione che fanno addizioni, sottrazioni, moltiplicazioni, ecc. Forse non sono buoni esempi?
Joshua Davis

1
@JoshuaDavis tutte queste "substratagie" sono casi speciali di una strategia: l'operazione aritmetica . hanno argomenti comuni (2 operandi) e producono un valore come risultato. praticamente facendo la stessa cosa (essendo scatole nere) in modo diverso, a seconda dell'implementazione. quindi non vedo alcun conflitto qui, ma, al contrario: bell'esempio =)
jungle_mole

7

Potrei sbagliarmi secondo me, ma tratto il comando come funzione da eseguire o reazione. Dovrebbero esserci almeno due giocatori: quello che richiede l'azione e quello che esegue l'azione. La GUI è un tipico esempio di schema di comando:

  • Tutti i pulsanti sulla barra degli strumenti dell'applicazione sono associati ad alcune azioni.
  • Button è l'esecutore in questo caso.
  • L'azione è il comando in questo caso.

Il comando è solitamente limitato a un ambito o area di business, ma non è necessario: potresti avere comandi che emettono una fattura, avvia un razzo o rimuove un file che implementa la stessa interfaccia (ad esempio un singolo execute()metodo) all'interno di un'applicazione. Spesso i comandi sono auto-contenenti, quindi non hanno bisogno di nulla dall'esecutore per elaborare l'attività che intendono svolgere (tutte le informazioni necessarie vengono fornite in fase di costruzione), a volte i comandi sono sensibili al contesto e dovrebbero essere in grado di scoprire questo contesto (Il comando Backspace dovrebbe conoscere la posizione del cursore nel testo per rimuovere correttamente il carattere precedente; Il comando Rollback dovrebbe scoprire la transazione corrente da ripristinare; ...).

La strategia è un po 'diversa: è più vincolata a un'area. La strategia può definire una regola per formattare una data (in UTC? Locale specifica?) (Strategia "data formatter") o per calcolare un quadrato per una figura geometrica (strategia "calcolatrice quadrata"). Le strategie sono in questo senso oggetti a peso mosca, che prendono qualcosa come input ("data", "figura", ...) e prendono delle decisioni sulla base di essa. Forse non il migliore, ma un buon esempio di strategia è quello connesso con l' javax.xml.transform.Sourceinterfaccia: a seconda che l'oggetto passato sia DOMSourceo SAXSourceo StreamSourcela strategia (= trasformatore XSLT in questo caso) applicherà regole diverse per elaborarlo. L'implementazione può essere semplice switcho coinvolgere un modello di catena di responsabilità .

Ma in effetti c'è qualcosa in comune tra questi due modelli: i comandi e le strategie incapsulano gli algoritmi all'interno della stessa area semantica.


1
Considero il comando come una funzione di callback o reazione. Dovrebbero esserci almeno due giocatori: uno che richiede l'azione e uno che esegue ... - Capisco cosa stai cercando di dire, ma eviterei di usare la parola 'richiamo', perché spesso la parola "callback" implica una chiamata asincrona e non è necessario eseguire invocazioni asincrone affinché il modello di comando sia utile. Caso in questione: Microsoft Word. I clic sui pulsanti della barra degli strumenti e le pressioni dei tasti di scelta rapida non richiamano comandi asincroni, ma possiamo apprezzare come il modello di comando sarebbe utile in questo caso
Jim G.

Sono d'accordo, anche se, come ha detto Jim, vorrei modificare per rimuovere il riferimento alla richiamata.
JARC

Grazie, ho fatto delle estensioni. Fammi sapere se sei d'accordo / in disaccordo.
dma_k

5

Comando:

Componenti di base:

  1. Comando dichiara un'interfaccia per comandi astratti comeexecute()
  2. Ricevitore sa come eseguire un particolare comando
  3. Invoker tiene ConcreteCommand , che deve essere eseguito
  4. Il cliente crea ConcreteCommand e assegnare Receiver
  5. ConcreteCommand definisce l'associazione tra Command e Receiver

Flusso di lavoro:

Il client chiama Invoker => Invoker chiama ConcreteCommand => ConcreteCommand chiama il metodo Receiver , che implementa il metodo Command astratto .

Vantaggio : il client non subisce modifiche in Command and Receiver. Invoker fornisce un accoppiamento libero tra Cliente e Ricevente. Puoi eseguire più comandi con lo stesso Invoker.

Il modello di comando ti consente di eseguire un comando su diversi ricevitori utilizzando lo stesso Invoker . Invoker non è a conoscenza del tipo di ricevitore

Per una migliore comprensione dei concetti, dai un'occhiata a questo articolo di JournalDev di Pankaj Kumar e l' articolo di dzone di James Sugrue oltre al link di Wikipedia.

Puoi usare il modello di comando per

  1. Disaccoppia l'invocatore e il destinatario del comando

  2. Implementare il meccanismo di callback

  3. Implementa funzionalità di annullamento e ripetizione

  4. Mantieni una cronologia dei comandi

java.lang.Threadè una buona implementazione del modello di comando . Puoi trattare Thread come invoker e classe che implementa Runnable come ConcreteCommonad / Receiver e run()metodo come Command .

La versione Annulla / Ripristina del modello di comando può essere letta nell'articolo di Theodore Norvell

Strategia:

Il modello strategico è molto semplice da capire. Usa questo modello quando

Sono disponibili più implementazioni per un algoritmo e l'implementazione dell'algoritmo può cambiare in fase di esecuzione a seconda di condizioni particolari .

Prendi un esempio del componente Tariffa del sistema di prenotazione della compagnia aerea

Le compagnie aeree vorrebbero offrire tariffe diverse durante periodi di tempo diversi - mesi di punta e non di punta. Durante i giorni di viaggio non di punta, vorrebbe stimolare la domanda offrendo sconti interessanti.

Aspetti chiave del modello di strategia :

  1. È un modello comportamentale
  2. Si basa sulla delega
  3. Cambia le viscere dell'oggetto modificando il comportamento del metodo
  4. Viene utilizzato per passare da una famiglia di algoritmi
  5. Modifica il comportamento dell'oggetto in fase di esecuzione

Post correlati con esempi di codice:

Utilizzando il modello Command Design

Esempio del mondo reale del modello di strategia


0

Per me, la differenza è di intenti. Le implementazioni di entrambi i modelli sono abbastanza simili, ma hanno scopi diversi:

  • Per una strategia, il componente che utilizza l'oggetto sa cosa fa l'oggetto (e lo userà per eseguire una parte del proprio lavoro), ma non gli importa come lo fa.

  • Per un comando, il componente che utilizza l'oggetto non sa né cosa fa il comando né come lo fa: sa solo come invocarlo. Il compito del chiamante è solo eseguire il comando: l'elaborazione eseguita dal comando non fa parte del lavoro principale del chiamante.

Questa è la differenza: l'oggetto che utilizza il componente sa o si preoccupa effettivamente di ciò che fa il componente? Il più delle volte questo può essere determinato in base al fatto che l'oggetto pattern restituisca un valore al suo invocatore. Se l'invocatore si preoccupa di ciò che fa l'oggetto pattern, probabilmente vorrà che restituisca qualcosa e sarà una strategia. Se non si preoccupa di alcun valore di ritorno probabilmente è un comando (nota, qualcosa come Java Callable è ancora un comando perché, sebbene restituisca un valore, al chiamante non interessa il valore - lo restituisce semplicemente a quanto originariamente fornito il comando).

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.