INTRODUZIONE AI DESIGN PATTERN
I design pattern sono soluzioni comuni e riutilizzabili a problemi ricorrenti nella progettazione del software. Invece di reinventare la ruota ogni volta che ci si confronta con un problema, i pattern offrono una struttura già testata e ben definita per affrontare le sfide comuni di sviluppo. Tra i principali contributi in questo ambito vi è il libro "Design Patterns: Elements of Reusable Object-Oriented Software", scritto dai cosiddetti Gang of Four (GoF) – Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides – che classifica i pattern in tre grandi categorie: creazionali, strutturali e comportamentali.
Categorie di Design Pattern
Creazionali: Questi pattern si concentrano sulla modalità con cui vengono create le istanze degli oggetti. Si preoccupano di astrarre il processo di instanziazione e di nascondere i dettagli di implementazione.
Strutturali: I pattern strutturali si concentrano sull'organizzazione e composizione delle classi o degli oggetti per formare strutture più grandi e complesse, senza modificarne il comportamento.
Comportamentali: I pattern comportamentali sono focalizzati sulle interazioni tra gli oggetti e sulla loro responsabilità nel sistema, facilitando la comunicazione e l'assegnazione dinamica di compiti.
Design Pattern Creazionali
Esempio: Factory Method
Il pattern Factory Method fornisce un'interfaccia per creare oggetti in una classe madre, ma permette alle sottoclassi di alterare il tipo di oggetto che sarà creato.
// Product Interface
interface Product {
void use();
}
// ConcreteProductA
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using Product A");
}
}
// ConcreteProductB
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using Product B");
}
}
// Creator Abstract Class
abstract class Creator {
public abstract Product createProduct();
public void someOperation() {
Product product = createProduct();
product.use();
}
}
// ConcreteCreatorA
class ConcreteCreatorA extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// ConcreteCreatorB
class ConcreteCreatorB extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// Main Class
public class Main {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
creatorA.someOperation();
Creator creatorB = new ConcreteCreatorB();
creatorB.someOperation();
}
}
Applicazione
Il Factory Method è utile quando una classe non conosce in anticipo quale tipo di oggetto deve creare, delegando la responsabilità della creazione alle sottoclassi.
Design Pattern Strutturali
Esempio: Adapter
Il pattern Adapter permette a classi con interfacce incompatibili di lavorare insieme, traducendo l'interfaccia di una classe in un'altra che il client si aspetta.
// Target Interface
interface Target {
void request();
}
// Adaptee Class (incompatibile)
class Adaptee {
public void specificRequest() {
System.out.println("Specific request in Adaptee");
}
}
// Adapter Class
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// Client Code
public class Main {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
adapter.request();
}
}
Applicazione
Il pattern Adapter viene utilizzato quando si ha bisogno di far collaborare classi con interfacce incompatibili senza modificare il loro codice originale.
Design Pattern Comportamentali
Esempio: Observer
Il pattern Observer definisce una dipendenza uno-a-molti tra oggetti, in modo che quando uno cambia il suo stato, tutti i suoi osservatori ne vengano notificati automaticamente.
import java.util.ArrayList;
import java.util.List;
// Observer Interface
interface Observer {
void update(String message);
}
// ConcreteObserver
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received update: " + message);
}
}
// Subject
class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// Main Class
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers("First Update");
subject.notifyObservers("Second Update");
}
}
Applicazione
L'Observer è molto utile nei casi in cui si desidera mantenere aggiornata automaticamente una serie di oggetti in base al cambiamento di stato di un altro oggetto.
Conclusione
I design pattern sono fondamentali per la progettazione di sistemi software ben strutturati e manutenibili. Conoscere i vari pattern, in particolare quelli definiti dai Gang of Four, aiuta a scegliere la soluzione ottimale per diversi problemi di progettazione, rendendo il codice più modulare, estensibile e riutilizzabile.
Comments
Post a Comment