Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seconda revisione capitolo Design Patterns #213

Draft
wants to merge 63 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
558c4e9
docs: #79 Inizio capitolo Design Patterns
Livio74 Jan 24, 2024
06756f0
chore: rimosso piramide.png
Cadienvan Jan 27, 2024
ec08192
Merge remote-tracking branch 'upstream/main' into add/design-patterns
Cadienvan Jan 27, 2024
3a97905
chore: rimosso piramide.png
Cadienvan Jan 27, 2024
3e0c694
Merge remote-tracking branch 'origin/main' into add/design-patterns
Cadienvan Jan 27, 2024
55712b4
Merge remote-tracking branch 'upstream/add/design-patterns' into add/…
Cadienvan Jan 27, 2024
1018d73
chore: riviste alcune porzioni di contenuto + aggiunte note
Cadienvan Jan 27, 2024
0004e20
chore: completamento Inizio capitolo Design Patterns
Livio74 Feb 4, 2024
7514232
chore: dependency Injection
Livio74 Feb 4, 2024
f4e1515
chore: dependency Injection
Livio74 Feb 4, 2024
4df0fda
chore: dependency Injection
Livio74 Feb 4, 2024
2ff61e6
feat: aggiustamenti dei primi paragrafi
Cadienvan Feb 6, 2024
15abf4b
Correzione su uso UML
Livio74 Feb 15, 2024
03e4e46
sul sito Refactoring Guru
Livio74 Feb 15, 2024
d168957
correzione di forma
Livio74 Feb 15, 2024
4b70784
Correzione di forma
Livio74 Feb 15, 2024
ce6ba33
Correzione di forma
Livio74 Feb 15, 2024
ff72a87
Correzione di forma
Livio74 Feb 15, 2024
54135b1
Correzione sulla Facilità di riuso e test del software
Livio74 Feb 15, 2024
500655b
Correzione di forma
Livio74 Feb 15, 2024
6288a7f
Spesso design pattern e programmazione ad oggetti sono strettamente l…
Livio74 Mar 10, 2024
e0cc1b2
aggiorna frase sulle soluzioni provate e testate
Livio74 Mar 10, 2024
309181c
sintesi migliore sulla comprensione dei design pattern
Livio74 Mar 10, 2024
83649af
meglio utilizzarli o no?
Livio74 Mar 10, 2024
32a1056
È importante sottolineare che non ci sono dei vincoli stringenti che …
Livio74 Mar 10, 2024
3162d4a
è possibile applicarli singolarmente, oppure applicarne più di uno
Livio74 Mar 10, 2024
9b685e4
update Principi SOLID
Livio74 Mar 10, 2024
cbf6bfa
In questo libro li definiremo brevemente evitando di listarli in mani…
Livio74 Mar 16, 2024
9167432
Le altre tipologie definite dalla GOF ...
Livio74 Mar 16, 2024
e357818
Abstract Factory
Livio74 Mar 16, 2024
3311775
Builder
Livio74 Mar 16, 2024
e7d10a8
Prototype
Livio74 Mar 16, 2024
757b221
Singleton
Livio74 Mar 16, 2024
5066b74
Products and Factories
Livio74 Mar 16, 2024
e012542
In generale dato un problema non sempre è semplice attribuirgli un de…
Livio74 Mar 16, 2024
2a4628a
Chain of responsibility
Livio74 Mar 16, 2024
a128f06
Adapter
Livio74 Mar 16, 2024
53f7283
Iterator
Livio74 Mar 16, 2024
03e6c62
Come visibile compare una struttura davanti al nostro client ...
Livio74 Mar 16, 2024
144f366
Model-View-Controller
Livio74 Mar 16, 2024
4549c22
meglio utilizzare i pattern o no
Livio74 Mar 26, 2024
64c716c
scomposizione problemi
Livio74 Mar 26, 2024
e724574
Pattern comportamentali
Livio74 Mar 26, 2024
d5c61a5
Proxy ed esempi
Livio74 Mar 26, 2024
c3c1020
Flyweight ed esempi
Livio74 Mar 26, 2024
79157ec
Façade
Livio74 Mar 26, 2024
bc98a90
Decorator
Livio74 Mar 26, 2024
51f06c7
Pattern strutturali
Livio74 Mar 26, 2024
fd7fda2
Esempio generico di costruzione oggetto
Livio74 Mar 26, 2024
5734606
Builder
Livio74 Mar 26, 2024
2c21e2d
Prototype
Livio74 Mar 26, 2024
7ee5a44
Può portare ad aumentare la complessità del codice ...
Livio74 Apr 7, 2024
5640cff
Apply suggestions from code review
Cadienvan Jun 25, 2024
15b0649
Apply suggestions from code review
Cadienvan Jun 25, 2024
ae547b3
Apply suggestions from code review
Cadienvan Jun 25, 2024
06d7b0a
eliminata frase come concordato con Serena e Michael
Livio74 Aug 24, 2024
d20784e
Aggiunta esempio dal sito Refactoring Guru
Livio74 Aug 24, 2024
ec3e331
far sparire la lista degli appunti sotto
Livio74 Aug 24, 2024
5ca6ae6
frase di riassunto in fondo come da accordi con Michael
Livio74 Aug 24, 2024
f10e0a6
Facciamo riferimento al Sito Refactoring Guru
Livio74 Aug 24, 2024
48b128e
Introduzione all'argomento e riferimento a Refactoring Guru
Livio74 Sep 6, 2024
f54f474
Apply suggestions from code review
Cadienvan Sep 16, 2024
f82c60c
Merge branch 'main' into add/design-patterns
Cadienvan Sep 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions docs/it/design-pattern.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
## Design Patterns

Il concetto di Design Patterns è definito su [Wikipedia](https://it.wikipedia.org/wiki/Design_pattern) come:

> Una soluzione progettuale generale ad un problema ricorrente.

Questo concetto, derivante da quello similare esistente in architettura, è comparso per la prima volta nel libro [Design Patterns - Elementi per il riuso di software ad oggetti](https://it.wikipedia.org/wiki/Design_Patterns) i cui autori, detti [Gang of Four](<https://it.wikipedia.org/wiki/Gang_of_Four_(scrittori)>), sono 4 importanti figure del panorama informatico internazionale: Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides.

Per capire meglio il concetto possiamo dire che ogni design pattern identifica un problema generalizzato da risolvere e associa ad esso una soluzione; questo generalmente viene rappresentato tramite uno schema UML, di supporto per comprendere meglio quanto proposto.

Spesso design pattern e programmazione ad oggetti sono strettamente legati poiché i primi vengono descritti e spiegati utilizzando gli oggetti.
Questo non vuol dire che, ad esempio, nella programmazione funzionale non vengano utilizzati, ma naturalmente necessitano di strutture differenti; in alcuni casi, a dire il vero, alcuni Design Patterns sono più facilmente implementabili con quest'ultimo paradigma.

Internet ha molte risorse valide sull'argomento, fra queste possiamo citare:

- [Il canale Youtube di Christopher Okhravi](https://www.youtube.com/@ChristopherOkhravi)
- [Design Patterns su Wikipedia Italiano](https://it.wikipedia.org/wiki/Design_pattern)
- [Design Patterns su Wikipedia Inglese](https://en.wikipedia.org/wiki/Design_pattern)

Questo capitolo ha come intento l'introduzione all'argomento, e non ha la presunzione di coprire ogni aspetto dei Design Pattern. Suggeriamo di affiancare la lettura alla navigazione del sito [Refactoring Guru](https://refactoring.guru/design-patterns/), che spiega i diversi Design Pattern evidenziando per ognuno vantaggi e svantaggi, mostrando esempi pratici ed esplicativi. Sono inoltre presenti esempi di codice acquistabili in vari linguaggi.

Il libro della Gang of Four identifica un elenco iniziale di design pattern, ognuno dei quali ha un nome che identifica la soluzione al problema generico che andrà a risolvere.
Durante lo sviluppo, può essere semplice individuare e applicare un design pattern mentre si analizza un problema specifico, ottenendo una serie di vantaggi, tra cui:

- **Facilità di riuso e test del software**: ogni design pattern è stato studiato e catalogato di modo da essere una soluzione (quasi) universale ad ogni problema analogo a quello descritto; di conseguenza è possibile utilizzare un'implementazione simile in diverse porzioni di codice. All'interno della letteratura, questi pattern sono solitamente accompagnati da suggerimenti e metodologie per eseguire del testing, il che rende il processo di scrittura dei test automatizzati più semplice ed efficace.
- **Miglior comprensione del codice**: essendo conosciuti e avendo un nome inequivocabile, è possibile riconoscere i design pattern e creare un linguaggio comune quando si documenta e sviluppa il software.
- **Soluzioni provate e testate**: essendo frutto dell'esperienza congiunta di più persone che sviluppano, e avvalorati da diversi casi d'uso nel corso degli anni, i design pattern difficilmente nascondono delle sorprese, e la loro adozione può garantire una soluzione _battle-tested_ e dimostrata rispetto ad un problema specifico.

Naturalmente, come ogni cosa nel mondo del software, i design pattern comportano degli svantaggi, tra cui:

1. Può portare ad aumentare la complessità del codice, per cui andrebbero utilizzati con parsimonia per non creare sovrastrutture non necessarie.
2. Per essere applicati nel modo migliore, i design pattern necessitano la conoscenza di alcune assunzioni, che però si maturano spesso tramite l'esperienza e la letteratura.
3. Le prestazioni spesso non coincidono con l'adozione di design pattern, in quanto lo scopo di questi ultimi è di risolvere un problema, non necessariamente in maniera ottimizzata.

**Come sempre, alla domanda se sia meglio utilizzarli o no, risponderemo con un cauto: _dipende_.**

In generale, non è sempre facile attribuire ad un problema esistente un dato design pattern e applicarlo; a volte la soglia tra l'applicazione di un pattern e un altro può essere molto sottile. Per questa ragione, è consigliato scomporre un problema complesso in altri più piccoli, utilizzando la metodologia nota come _divide et impera_, che rende più semplice individuare dei pattern specifici per i singoli problemi scomposti.
Non sempre, però, è possibile scomporre in questo modo un problema, e alle volte bisogna arrendersi alla impossibilità di applicare uno specifico pattern, adottando invece il puro buon senso e arrivando alla soluzione con gli strumenti che si hanno a disposizione.

è possibile applicarli singolarmente, oppure applicarne più di uno; chiaramente una aderenza maggiore implica la facilità nel riconoscerli da parte di altri/e dev che conoscono l'argomento.

Generalmente dopo un refactoring, la nostra applicazione sarà più aderente ai [principi di sviluppo software SOLID](https://it.wikipedia.org/wiki/SOLID) il che implica il riuso e la facilità di test, come accennato in precedenza.\

Oltre al libro sui Design Patterns in questione ne sono stati introdotti altri che vedremo successivamente.\
Cadienvan marked this conversation as resolved.
Show resolved Hide resolved
Il libro della Gang of Four (GOF) suddivide i Design Pattern in 3 categorie:

1. Patterns creazionali
2. Patterns strutturali
3. Patterns comportamentali

## Patterns creazionali

I [Pattern creazionali](https://refactoring.guru/design-patterns/creational-patterns) definiscono uno schema progettuale che in particolare si concentra sulla creazione degli oggetti che concorrono a risolvere un determinato problema.
In questo contesto indichiamo come _prodotti_ gli oggetti creati utilizzando un oggetto generalmente denominato Factory (tradotto in _fabbrica_) che, al suo interno, ne definisce la logica di costruzione, la quale risulta isolata dall'esterno.
Le altre tipologie definite dalla GOF, che sono la strutturale e la comportamentale, si distiguono da questa perché presuppogono già l'esistenza di tutti gli oggetti coinvolti.

I pattern creazionali definiti dalla GOF sono:

- Factory Method : definisce, nella classe Factory, uno o più metodi detti appunto factory methods che creano i nostri oggetti prodotto.
- Abstract Factory : serve a creare famiglie (possibilmente) fisse di oggetti "prodotto" sempre utilizzando una interfaccia/classe chiamata appunto Abstract factory dove anche gli oggetti "prodotto" sono generici (anch'essi utilizzano un'interfaccia o classe astratta).
- Builder : definisce una particolare classe factory che consente di costruire oggetti complessi step-by-step. È quindi possibile produrre diverse tipologie e rappresentazioni di un oggetto componendolo in base alle proprie necessità.
- Prototype : permette di costruire oggetti clonando oggetti già esistenti. Per esempio, JavaScript utilizza proprio il concetto di _prototype_ per estendere gli oggetti. Nota a margine: parliamo proprio degli oggetti e non delle classi che sono state introdotte successivamente.
- Singleton : permette di costruire un oggetto garantendo che ne verrà creata una sola istanza

Come già detto i confini non sono ben definiti per cui, ad esempio, un oggetto complesso potrebbe essere creato tramite un builder e, se una parte dovesse richiedere una clonazione con un successivo raffinamento, sarà necessario utilizzare anche un Prototype che si occuperà della parte di clonazione.
Se non ci fosse la possibilità di effettuare una separazione netta si potrebbe utilizzare il Builder o il Prototype.
Cadienvan marked this conversation as resolved.
Show resolved Hide resolved

## Patterns strutturali

I [Pattern strutturali](https://refactoring.guru/design-patterns/structural-patterns) definiscono uno schema progettuale atto a risolvere problematiche inerenti alla struttura degli oggetti, di modo da renderli flessibili ed efficienti; capiremo meglio questo concetto andando a vedere brevemente tutti i design pattern appartenenti a questa categoria.

I pattern strutturali definiti dalla GOF sono:

- Adapter: è un pattern che permette di interporre tra due interfacce che devono comunicare tra loro un _adattatore_, che traduce le chiamate in entrambe le direzioni nella maniera che ognuna di essere si aspetta. Fornisce una soluzione astratta al problema della interoperabilità fra interfacce. Nella vita reale abbiamo ad esempi gli adattatori delle spine.
- Bridge: è un design pattern strutturale che consente di dividere una classe di grandi dimensioni o un insieme di classi strettamente correlate in entità separate, astrazione e implementazione, che possono essere sviluppate indipendentemente l'una dall'altra. Solitamente questo pattern, per via del modo in cui è implementato, viene chiamato anche _composition-over-inheritance_.
- Decorator: è un pattern che permette di aggiungere funzionalità attraverso il wrapping, cioè incapsulando un oggetto esistente.
Di conseguenza il nuovo oggetto avrà sia le funzionalità dell'oggetto originale che le nuove funzionalità aggiunte tramite decoratore.
- Façade: è un pattern che permette la semplificazione di un insieme complesso di classi o parti di un sistema, tramite la creazione di classi _di facciata_ che espongano solo le funzionalità più utili.
- Flyweight: è un pattern che permette di ottimizzare l'utilizzo della memoria di un sistema tramite il riutilizzo di membri comuni tra molti oggetti, senza doverne istanziare costantemente di nuovi. Ad esempio, se ho la necessità di realizzare 1.000 oggetti della classe _Dog_ che, tramite un metodo _Move_, modificano la propria posizione, è molto più sensato separare la classe _Dog_ in due classi, _Dog_ e _MovingDog_, collezionando nella prima le informazioni _statiche_, come razza e nome, mentre nella seconda le informazioni di _stato_ o _dinamiche_, come la posizione.
- Proxy: si interpone tra un oggetto (di solito di servizio) e il mondo esterno con cui comunica, utilizzando la stessa interfaccia, ma alterandone il comportamento. Un esempio sono i Proxy server che agiscono da intermezzo tra la propria macchina e il web, alterando e verificando ogni chiamata in ingresso e in uscita da essi, garantendo anonimato e un buon grado di sicurezza.


## Patterns comportamentali

I [Pattern comportamentali](https://refactoring.guru/design-patterns/behavioral-patterns) definiscono uno schema progettuale che in particolare risolve problematiche di comportamento degli oggetti definiti nel pattern. Generalmente questo comportamento si riflette in particolare sugli algoritmi e sulle responsabilità degli oggetti stessi.

I pattern comportamentali definiti dalla GOF sono:

- Chain of responsibility: questo pattern permette di separare gli oggetti che invocano richieste dagli oggetti che le gestiscono. In pratica viene definita una catena di oggetti dove la richiesta viene propagata finchè uno di quelli implementati non decide di gestirla. Ogni elemento della catena viene chiamato _handler_.
- Command: permette di isolare il codice che esegue una azione più o meno complessa dal client che la esegue oppure prendere una richiesta, memorizzarla in modo che possa essere eseguita in un secondo momento ad esempio dopo un certo evento.
- Iterator: permette di visitare tutti gli elementi di un altro oggetto, detto contenitore, senza dipendere dalla struttura interna di esso.
Un esempio tipico può essere il cursore per la lettura di una datasource.
- Mediator: incapsula l'interazione fra i vari oggetti di un loro insieme facendo in modo che la comunicazione col client venga gestita sempre da una unica entità favorendo il disaccoppiamento fra gli oggetti stessi.
- Memento: si occupa di memorizzare lo stato corrente di un altro oggetto detto Originator cercando di non violare l'incapsulamento. Può essere utile nei casi in cui si possa avere uno storico dell'oggetto stesso richiedendo al Memento il ripristino di uno stato precedente. (Il cosiddetto Undo/Redo)
- Observer: è una struttura formata da un Observer che osserva un cambiamento di stato di un Subject (o Soggetto) che possiamo definire Observable (Osservabile o Osservato) che fa appunto accadere quando lo stato all'interno di esso cambia. Esistono Librerie con RxJS si basano principalmente su questo pattern. Quando l'Observable cambia stato tutti gli Observer registrati ricevono l'informazione del cambiamento.
- State: è di fatto riconducibile ad un diagramma a stati finiti; consente ad un oggetto di modificare il proprio comportamento al cambiamento (ed in base) al suo stato interno.
- Strategy: permette di scegliere più comportamenti di un algoritmo (generalmente una variante di esso) a runtime associandolo (incapsulandolo) in una singola classe che lo implementa
- Template method: è generalmente un metodo che implementa lo scheletro di un algorirmo e al suo interno possono essere chiamate parti (generalmente step) utilizzando la sovrascrittura dei passi senza dover cambiare la struttura del client chiamante.
- Visitor: in esso si separa una struttura dati dalla logica di attraversamento (visita) dell'algoritmo di visita e quindi dalle operazioni fatte su di essa. Gli algoritmi di visita possono cambiare senza cambiare la struttura del client.

## Altri pattern

Come già detto la Gang of Four ha iniziato a definirli e successivamente sulla loro falsa riga ne sono stati individuati altri che descriveremo brevemente di seguito.

- Client/Server: è un pattern cosiddetto architetturale poichè può essere ad esempio l'architettura del prodotto che si vuole sviluppare. Esistono due "componenti" il client che effettua richieste ed il server che le riceve e risponde ad uno o più client.\
Esempio classico sono quasi tutti i server di database che ad ogni richiesta, ad esempio di esecuzione di una query, rispondono con i risultati.
- Model-View-Controller: è un pattern dove definiamo due entità separate, una per il considdetto _model_, ossia l'entità che vogliamo rappresentare e che contiene i suoi dati, contestualmente al View, che definisce come mostrarla all'utente esterno e ne permette l'interazione; infine esiste il Controller che serve a descrivere le interazioni fra i due.
- Dependency Injection: è un pattern che permette di iniettare una dipendenza in una classe attraverso l'Inversion of control. Questo viene fatto iniettando un'interfaccia o una classe astratta in modo da poter cambiare la sua implementazione in qualsiasi momento.\
Abbiamo 3 tipi di iniezioni:

- Injection nel costruttore
- Injection tramite setter
- Injection tramite interfaccia

In questo libro li abbiamo definiti brevemente evitando di descriverli in maniera accademica; questo capitolo è infatti un modo per approcciarsi al tema e approfondire successivamente, grazie anche all'esistenza di numerose risorse, che li dettagliano in maniera più puntuale come quelle che abbiamo già elencato.
Loading