{"id":2898,"date":"2017-09-18T09:56:40","date_gmt":"2017-09-18T07:56:40","guid":{"rendered":"http:\/\/ardea.srl\/?p=2898"},"modified":"2019-02-06T17:36:52","modified_gmt":"2019-02-06T16:36:52","slug":"command-design-pattern","status":"publish","type":"post","link":"https:\/\/ardea.srl\/it\/command-design-pattern\/","title":{"rendered":"Command Design Pattern: un esempio di applicazione"},"content":{"rendered":"<p>Sai usare un <em>Command Design Pattern<\/em>?\u00a0Ti sei mai chiesto cos\u2019\u00e8 un <em>Abstract Factory<\/em>? O com\u2019\u00e8 fatto un <em>Proxy<\/em>? In questo articolo introduciamo i <em>Design Pattern<\/em> raccontandoti un caso reale di applicazione.<\/p>\n<p><!--more--><\/p>\n<h2>Il problema<\/h2>\n<p>Qualche anno\u00a0fa un cliente ci ha chiesto di rifare un <strong>componente di un&#8217;applicazione<\/strong> scritta con Java.<\/p>\n<p>Il\u00a0componente riceveva informazioni (o messaggi) dall\u2019interfaccia utente e da altri\u00a0dispositivi fisici esterni: tastiera dedicata, lettori di carte, scanner\u2026 e trasformava\u00a0i messaggi ricevuti in azioni dell\u2019applicazione. Non c&#8217;era\u00a0un ordine predefinito con cui le fonti inviavano i messaggi e i passi che l\u2019applicazione doveva eseguire dipendevano sia dalle informazioni, sia dall\u2019esito della loro elaborazione.<\/p>\n<p>L\u2019<strong>implementazione<\/strong> esistente era <strong>fragile<\/strong>: qualche volta\u00a0si bloccava\u00a0e\u00a0l\u2019applicazione doveva essere chiusa e riavviata.<\/p>\n<h2>L\u2019approccio <i>semplice<\/i><\/h2>\n<p>Per mostrarti la differenza tra l\u2019approccio procedurale e quello a oggetti basato sul <em>Design Pattern<\/em>\u00a0&#8216;<em>Command&#8217;<\/em>, cominciamo a vedere\u00a0una <strong>soluzione procedurale<\/strong>.<\/p>\n<p>Cominciamo a costruire un ciclo principale che serve per ricevere ed elaborare tutti i messaggi dalle varie fonti.<\/p>\n<p>Potrebbe assumere questo aspetto:<\/p>\n<pre>while (true) {\r\n  Object message = readNextMessage();\r\n  \/\/ fai qualcosa con il messaggio\r\n}<\/pre>\n<p>Il primo problema \u00e8: <strong>come gestiamo il messaggio?<\/strong>\u00a0Ogni fonte manda messaggi con struttura differente che devono essere elaborati in modi diversi.<\/p>\n<p>Per riconoscere il tipo di messaggio potremmo aggiungergli un attributo\u00a0che lo qualifica (<code>type)<\/code>e sulla base del suo valore decidere come procedere:<\/p>\n<pre>switch (message.type) {\r\n  case INPUT_FROM_KEYBOARD:\r\n    \/\/Elabora messaggio da tastiera\r\n  case INPUT_FROM_SCANNER:\r\n    \/\/Elabora messaggio da scanner\r\n  \u2026\r\n}<\/pre>\n<p>Le diverse\u00a0informazioni che accompagnano il messaggio possono essere registrate in una mappa. Ad esempio, per leggere il valore del tasto premuto dall\u2019utente sulla tastiera, potremmo scrivere:<\/p>\n<pre>value = message.get(\u201ckey\u201d);<\/pre>\n<p>Il secondo problema \u00e8: <strong>come facciamo l\u2019elaborazione dei messaggi?<\/strong> Possiamo\u00a0pensare a un metodo dedicato per ogni tipo di messaggio.<\/p>\n<p>Bene. Ma c\u2019\u00e8 un altro problema: ogni elaborazione produce un risultato che pu\u00f2 richiedere ulteriori passaggi, dipendenti dal risultato stesso e dal tipo di messaggio.<\/p>\n<p>Ora puoi ben immaginare il codice che deriva\u00a0da questa soluzione:<\/p>\n<ul>\n<li><em>if<\/em> nidificati a pi\u00f9 livelli<\/li>\n<li>istruzioni duplicate<\/li>\n<li>metodi mediamente lunghi.<\/li>\n<\/ul>\n<p>Insomma questa strada genera\u00a0un <strong>codice molto complicato<\/strong>, difficile da scrivere, da capire e da manutenere.<\/p>\n<h2>L\u2019approccio scelto: applichiamo il <em>Design Pattern\u00a0&#8216;Command&#8217;<\/em><\/h2>\n<p>La prima considerazione che abbiamo fatto \u00e8 stata questa:\u00a0ogni messaggio ricevuto dall\u2019esterno poteva essere rappresentato con un oggetto a s\u00e9 stante.\u00a0Infatti ogni messaggio aveva una struttura diversa e conteneva tutte le informazioni necessarie per la successiva elaborazione: con questa premessa l\u2019elaborazione poteva essere fatta dall\u2019oggetto stesso, invece che da una funzione esterna.<\/p>\n<p>Non volevamo ricorrere all\u2019uso di <em>instanceof<\/em> e del <em>cast<\/em> per identificare i vari tipi di messaggio: questa soluzione\u00a0avrebbe penalizzato l\u2019estensibilit\u00e0 del componente e la sua futura evoluzione.\u00a0L\u2019alternativa era dare a tutti i messaggi la stessa\u00a0interfaccia e contare sul <strong>polimorfismo<\/strong>.<\/p>\n<p>I passi opzionali e variabili da eseguire dopo l\u2019elaborazione dei messaggi potevano essere modellati nello stesso modo, cio\u00e8 definendo <strong>un\u2019interfaccia comune<\/strong>\u00a0per rendere pi\u00f9 semplice e omogenea l\u2019interazione.<\/p>\n<p>Abbiamo ritenuto\u00a0che il Design Pattern <em>Command<\/em> fosse la soluzione giusta. Cos\u00ec abbiamo deciso\u00a0di rappresentare\u00a0ogni elaborazione e ogni passo successivo con\u00a0un <em>Command<\/em> di interfaccia:<\/p>\n<pre>interface Operation {\r\n  public void execute(Context ctx);\r\n}\r\n<\/pre>\n<p>Ecco come si presentava una classe che implementava questa interfaccia:<\/p>\n<pre>class MessageFromKeyboard implements Operation {\r\n  private String key;\r\n\r\n  public void execute(Context ctx) {\r\n    \/\/ elabora i dati e produce un risultato\r\n    \/\/ crea i passi successivi e li inserisce nella lista delle operazioni da eseguire tramite Context)\r\n  }\r\n}<\/pre>\n<p><em>Context<\/em> rappresentava un oggetto che l\u2019operazione poteva utilizzare per svolgere compiti particolari, per\u00a0esempio registrare informazioni sul <i>log<\/i> dell\u2019applicazione e accodare i successivi oggetti di tipo <em>Operation<\/em>.<\/p>\n<p>Alla fine il componente da sviluppare\u00a0assumeva\u00a0l\u2019aspetto di un <em>CommandProcessor<\/em>, un oggetto che esegue la logica di altri\u00a0oggetti di tipo <em>Operation<\/em>.<\/p>\n<h2>La soluzione<\/h2>\n<p>Con questa idea il problema diventava\u00a0gestibile: non era pi\u00f9 necessario prefigurarsi tutti gli scenari possibili, corrispondenti a numerose combinazioni di <em>if<\/em>. Ogni <em>Command<\/em> poteva svolgere il proprio lavoro in modo lineare, valutare il risultato e se necessario costruire i passi successivi come ulteriori <em>Command<\/em> da mettere in coda perch\u00e9 il <em>CommandProcessor<\/em> li elaborasse.<\/p>\n<p>Questo approccio aveva un altro indiscutibile vantaggio: ogni singolo <em>Command<\/em> poteva essere isolato e testato, permettendoci di costruire una suite di test automatici che garantivano il corretto funzionamento di tutte le parti del componente. Un passo chiave per il successo dell&#8217;intero progetto.<\/p>\n<p>La soluzione prefigurata\u00a0prometteva bene e cos\u00ec abbiamo cominciato a sviluppare il componente.\u00a0A mano a mano che procedevamo nello sviluppo la soluzione si mostrava corretta. Non solo: era tanto flessibile da accogliere anche tutte quelle funzionalit\u00e0 necessarie ma non prevedibili all&#8217;inizio.<\/p>\n<p>Dopo tre\u00a0mesi di sviluppo il componente era pronto: integrato nell\u2019applicazione con facilit\u00e0, \u00e8 entrato in produzione presso tutti i clienti senza manifestare problemi.<\/p>\n<h2>Conclusione<\/h2>\n<p>I <em>Design Pattern<\/em> sono uno strumento prezioso per progettisti e sviluppatori di software. Spesso aiutano a trovare soluzioni efficaci che migliorano il lavoro di codifica, semplificano la scrittura e rendono pi\u00f9 economica la manutenzione delle applicazioni.<\/p>\n<p>Ma c&#8217;\u00e8 una\u00a0premessa fondamentale per poterli usare bene: capire e conoscere a fondo\u00a0ciascun <em>Pattern<\/em>.<\/p>\n<p>Se ancora non padroneggi\u00a0i <em>Design Pattern<\/em>\u00a0puoi seguire <a href=\"http:\/\/ardea.srl\/shop\/sviluppo-software\/progettazione\/design-pattern-java\/\">il nostro corso<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sai usare un Command Design Pattern?\u00a0Ti sei mai chiesto cos\u2019\u00e8 un Abstract Factory? O com\u2019\u00e8 fatto un Proxy? In questo articolo introduciamo i Design Pattern raccontandoti un caso reale di applicazione.<\/p>\n","protected":false},"author":2,"featured_media":2950,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[156],"class_list":["post-2898","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-design-pattern"],"_links":{"self":[{"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/posts\/2898","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/comments?post=2898"}],"version-history":[{"count":17,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/posts\/2898\/revisions"}],"predecessor-version":[{"id":3394,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/posts\/2898\/revisions\/3394"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/media\/2950"}],"wp:attachment":[{"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/media?parent=2898"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/categories?post=2898"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ardea.srl\/it\/wp-json\/wp\/v2\/tags?post=2898"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}