Design Pattern Exposed: Strategy Pattern



In questo blog scopriremo lo Strategy Design Pattern, che viene utilizzato per creare una famiglia intercambiabile di algoritmi che possono essere scelti dinamicamente.

'

Benvenuti nel primo post della serie 'Design Patterns Exposed'. In questa serie scopriremo da zero ogni Design Pattern.





La semplice conoscenza di un linguaggio di programmazione e dei suoi costrutti non ti renderà un programmatore o sviluppatore migliore. Richiede la conoscenza di Design Patterns per creare software che funzionerà oggi e anche in futuro.

Molti sviluppatori hanno già riscontrato quei problemi di progettazione che stai affrontando in questo momento o che affronterai in futuro. Hanno specificato un modo standard per affrontare il problema. Quindi, utilizzando Design Patterns ottieni il vantaggio di utilizzare tecniche collaudate.



Ogni Design Pattern serve per risolvere un particolare tipo di situazione, potrebbero esserci situazioni in cui è possibile utilizzare più di un Design Pattern.

La maggior parte dei programmatori cerca semplicemente di risolvere il problema che deve affrontare senza preoccuparsi di schemi di progettazione, codice ridondante o persino accoppiamenti stretti. Ma i bravi programmatori iniziano diversamente. Pensano ai requisiti di oggi, ai requisiti futuri, alla manutenzione del codice e alla riutilizzabilità del codice.

I bravi programmatori non hanno fretta di iniziare a scrivere codice una volta ottenuti i requisiti. Si siedono e pensano al problema se il loro design funzionerà. Se sì, se funzionerà dopo 6 mesi, quando i requisiti cambieranno.



I bravi programmatori prendono carta e penna e iniziano a progettare le loro classi e le relazioni tra le classi. Cercano di ottenere un accoppiamento lento e un'elevata coesione nel loro design, mentre fanno tutto questo hanno in mente i Principi orientati agli oggetti. Non entrano immediatamente nel codice di basso livello. Per progettare un software flessibile e riutilizzabile, dovresti seguire questo approccio altrimenti ti ritroverai sempre a modificare il codice che avevi scritto in precedenza.

C'è solo una cosa che è costante nell'industria del software ed è Modificare. I requisiti continueranno sicuramente a cambiare. Quindi come progettiamo il software che il tuo codice possa facilmente adattare alle esigenze future? Per questo devi iniziare presto e progettarlo in modo tale che i requisiti futuri non interrompano il codice precedente.

Come posso fare ciò?

Bene, può essere fatto seguendo i principi di progettazione e i modelli di progettazione basati su tali principi.

Ora, tuffiamoci nella programmazione e iniziamo il viaggio per diventare un programmatore migliore. In questo post, scopriremo uno dei pattern più importanti - Schema strategico .

Quando dico il più importante, riflette sul problema comune che viene risolto da Strategy Pattern.

Cos'è il pattern strategico?

Ecco la definizione direttamente dal libro 'Gang of Four': 'Lo Strategy Pattern viene utilizzato per creare una famiglia intercambiabile di algoritmi da cui viene scelto il processo richiesto in fase di esecuzione'.

Nel caso tu lo sianon riesco a capire, non preoccuparti, lo spiegheremo in unpiù semplicemodoper tecapire.

Prima di tutto comprendiamo il problema e poi vedremo come Strategy Pattern può risolverlo.

Nel diagramma UML sopra, abbiamo la classe astratta Animal e due classi concrete, Dog e Bird, che si estendono dalla superclasse Animal.

Quindi definiamo una classe astratta di Animali e due classi concrete, Cane e Uccello.

Cosa ne pensi del design di cui sopra? C'è un grosso errore nel nostro design.

Tutti gli animali non possono volare, come nel caso precedente un cane non può volare. Ma ha ancora un comportamento 'volante'.

Abbiamo commesso un errore scrivendo il metodo abstract fly () nella classe Animal. Questo design costringerà ogni sottoclasse Cane, Uccello, Pinguino, Coccodrillo, Oca ecc. Ad implementare il metodo fly ().

python cos'è __init__

Avremmo dovuto capire che il volo è un'abilità che non tutti gli animali avranno. Fornendo il metodo fly () nella classe Animal abstract abbiamo impostato l'abilità di volo in tutte le sottoclassi che non è corretta per tutte le sottoclassi di animali.

Potresti pensare qual è il problema nell'implementazione del metodo fly nelle sottoclassi. Sebbene tu possa implementare il metodo fly () nelle sottoclassi di Animali non volanti per stampare semplicemente 'Non posso volare'. Ma il problema è che stai ancora dando il comportamento della mosca agli animali non volanti. Questo non è corretto.

Come ci si sente a chiamare dog.fly () o crocodile.fly ().

Quindi, ora abbiamo capito che il nostro progetto non è corretto e dovremmo rimuovere il metodo fly () dalla sottoclasse Animal.

Qual è l'altro modo di progettare le nostre classi in modo tale che il nostro design non imponga a tutte le sottoclassi di animali di avere un comportamento di volo.

Una soluzione che viene subito in mente è che possiamo creare un'interfaccia volante con il metodo di volo e solo gli animali in grado di volare implementeranno quell'interfaccia di volo. In questo modo non applicheremo tutte le sottoclassi di Animali per definire un comportamento di mosca. Quindi codifichiamo questo approccio progettuale.

Ora, la nostra classe Animal apparirà come il codice seguente dopo aver rimosso il metodo fly dalla classe Animal.

Ora definiamo l'interfaccia di volo

Ora, la classe del cane verrà modificatacomeil codice seguente e non è necessario che abbia il comportamento di volo.

Vediamo alcune delle nostre sottoclassi di animali che avranno un comportamento di volo.

Abbiamo risolto il nostro problema precedente, ma ci siamo imbattuti in un nuovo problema e questo è 'Code Duplication'.

Diciamo che avremo 100 diverse sottoclassi di Animali volanti. Dobbiamo duplicare il codice per il comportamento di volo poiché l'interfaccia di volo non può fornire alcuna implementazione per il comportamento di volo, e in seguito se vogliamo cambiare l'implementazione del metodo fly () in qualsiasi sottoclasse dovremo aprire quella classe e cambiare il codice, che è male. Ci manca qualcosa di grande e, cioè, non possiamo cambiare il comportamento di volo di una classe in fase di esecuzione.

Ma non preoccuparti, Strategy Pattern è lì per farti uscire da questo problema.

Quindi eseguiamo il refactoring del nostro codice per utilizzare Strategy Pattern.

L'interfaccia di volo rimarrà la stessa di prima. Ora, piuttosto che ogni sottoclasse volante che implementa l'interfaccia di volo stessa, definiremo classi concrete separate che implementeranno comportamenti di volo diversi. Vediamo come farlo.

Quindi, come funziona, vediamo la TestClass

Utilizzando Strategy Pattern, ora siamo in grado di modificare il comportamento di volo di qualsiasi animale in fase di esecuzione e questo senza imporre a nessuna sottoclasse di specificare il comportamento di volo stesso.

Quando utilizzare Strategy Pattern?

Quando si desidera essere in grado di modificare dinamicamente il comportamento in fase di esecuzione.

Per essere sicuri di comprendere chiaramente lo Strategy Pattern, facciamo un altro esempio.

Nella suddetta classe Dipendenti stiamo impostando la retribuzione del dipendente in base alla sua designazione. Se un dipendente è uno “stagista” aggiungiamo il 10% di bonus allo stipendio base per calcolare la retribuzione effettiva.

Se un dipendente è uno 'sviluppatore web', aggiungiamo il 20% di bonus allo stipendio base per calcolare la retribuzione effettiva e il processo simile segue per altri tipi di dipendenti. Sebbene il nostro algoritmo per il calcolo della paga effettiva sia molto semplice per renderlo più facile da capire, ma la maggior parte delle volte include molti confronti e calcoli.

Allora, cosa c'è di sbagliato nel codice di classe dipendente?

Ebbene, il codice per il calcolo della paga (getPay ()) è statico. Supponiamo che io voglia cambiare il bonus per 'Intern' dal 10% al 14%. Dovrò aprire il codice della classe Employee e cambiarlo.

E un altro problema è che non posso modificare l'algoritmo di pagamento di un dipendente in fase di esecuzione. Allora, come farlo? Il modello di strategia è utilizzato specificamente per gestire questo tipo di problema.

Eseguiamo il refactoring del codice per utilizzare Strategy Pattern.

Definirò diversi algoritmi per calcolare la paga. Quindi potrò utilizzare uno qualsiasi di questi algoritmi per calcolare la retribuzione in fase di esecuzione.

Ora vediamo come cambierà la classe Employee.

Nota: Ho rimosso la logica di calcolo della retribuzione dalla classe Employee e ho creato un metodo PayAlgorithm () impostato attraverso il quale imposterò il PayAlgorithm che voglio utilizzare per il calcolo della retribuzione.

Questo mi darà la flessibilità di calcolare la paga specificando dinamicamente qualsiasi PayAlgorithm in fase di esecuzione. Inoltre, tieni presente che in seguito, se devo modificare la logica di calcolo della paga, posso creare un nuovo PayAlgorithm e utilizzarlo per calcolare la paga. Non ho bisogno di cambiare il codice precedente, non è fantastico?

Quindi vediamo che funziona.

Spero che tu abbia capito molto bene lo Strategy Pattern. Il modo migliore per imparare qualcosa è esercitarsi.

In caso di domande relative a Strategy Pattern o qualsiasi altro Pattern, lascia le tue domande di seguito.

Attenzione al prossimo post, dove scopriremo uno dei Design Pattern più popolari, Factory Pattern.

Fino ad allora puoi scaricare il codice per giocare con esso e assicurarti di cementare lo Strategy Pattern nella tua testa.

Hai domande per noi? Menzionateli nella sezione commenti e vi risponderemo.

Post correlati: