At any given moment, somewhere in the world someone struggles with the same software design problems you have. You know you don't want to reinvent the wheel (or worse, a flat tire), so you look to Design Patterns--the lessons learned by those who've faced the same problems. With Design Patterns, you get to take advantage of the best practices and experience of others, so that you can spend your time on...something else. Something more challenging. Something more complex. Something more fun.
You want to learn about the patterns that matter--why to use them, when to use them, how to use them (and when NOT to use them). But you don't just want to see how patterns look in a book, you want to know how they look "in the wild". In their native environment. In other words, in real world applications. You also want to learn how patterns are used in the Java API, and how to exploit Java's built-in pattern support in your own code.
You want to learn the real OO design principles and why everything your boss told you about inheritance might be wrong (and what to do instead). You want to learn how those principles will help the next time you're up a creek without a design pattern.
Most importantly, you want to learn the "secret language" of Design Patterns so that you can hold your own with your co-worker (and impress cocktail party guests) when he casually mentions his stunningly clever use of Command, Facade, Proxy, and Factory in between sips of a martini. You'll easily counter with your deep understanding of why Singleton isn't as simple as it sounds, how the Factory is so often misunderstood, or on the real relationship between Decorator, Facade and Adapter.
With Head First Design Patterns, you'll avoid the embarrassment of thinking Decorator is something from the "Trading Spaces" show. Best of all, in a way that won't put you to sleep! We think your time is too important (and too short) to spend it struggling with academic texts.
If you've read a Head First book, you know what to expect--a visually rich format designed for the way your brain works. Using the latest research in neurobiology, cognitive science, and learning theory, Head First Design Patterns will load patterns into your brain in a way that sticks. In a way that lets you put them to work immediately. In a way that makes you better at solving software design problems, and better at speaking the language of patterns with others on your team.
In generale ho trovato molto interessante l’argomento sui Design Pattern descitto in questo libro.
Vengono descritti in dettaglio i più popolari pattern di design. Ovviamente non ci sono pattern giusti e pattern sbagliati, tutto dipende dal contesto nel quale sono utilizzati.
Quello che non viene molto approfondito in questo libro è la parte che descrive QUANDO utilizzare questi pattern. Solo l'ultimo capitolo tratta questo aspetto.
Non mi è piaciuta molto la "forma" del libro. Ci sono troppe vignette, immagini, dialoghi e battute. Capisco che sono tutte cose che rendono il libro più leggero e leggibile, ma in questo caso si è andato decisamente oltre.
Ho trovato utile l'utilizzo dei diagrammi delle classi UML per descrivere la struttura dei pattern. Gli elementi UML utilizzati sono: - Blocco: classe o interfaccia. - Freccia continua con punta piena: classe A eredita da classe B (extends). - Freccia tratteggiata con punta piena: classe A implementa interfaccia B (implements). - Freccia continua con punta vuota: classe A ha (una variabile di tipo) interfaccia/classe B (has a).
Pattern descritti nel libro: * Strategy Pattern: - Per le cose che cambiano puoi usare delle interfacce a parte. - Programma sull'interfaccia, non sull'implementazione. Le interfacce hanno generalmente il suffisso "behaviour". - Invece di usare classi che estendere da classi padre (o classi astratte), è meglio avere variabili di tipo interfaccia. In questo modo le puoi cambiare a runtime. Ogni interfaccia può venire usata per implementare una famiglia di algoritmi.
* Observer Pattern: É presente in java.util package (ma ha limitazioni: Observable è una classe non un’interfaccia, quindi limiti il suo utilizzo. Infatti, puoi estendere solo una classe, ma puoi più interfacce). È usato anche nell'ActionListener di JavaBeans. - ci sono due interfacce: Observable (o Subject), Observer. - definisce 1-to-* relazione tra Observable e Observer - quando lo stato di un Observable cambia, gli Observer vengono notificati - fornire meno informazioni possibili tra oggetti che comunicano tra loro - Observable contiene i metodi per gestire gli observer: registerObserver, removeObserver, notifyObservers(). - La classe che eredita da Observer ha un riferimento a Observable, perché è l'osservatore che decide se registrarsi o annullare la registrazione.
* Decorator Pattern: consente di aggiungere nuove funzionalità ad oggetti già esistenti. Questo viene realizzato costruendo una nuova classe decoratore che "avvolge" l'oggetto originale. Al costruttore del decoratore si passa come parametro l'oggetto originale. - Esempio sono: In java.io: FileInputStream è il componente, BufferedInputStream e LineNumberInputStream sono decoratori (FilterInputStream è il decoratore astratto). - usa extends ma non per gestire il comportamento. Il comportamento viene usato con la composizione: nei metodi si usa il "sotto-componente" non l'oggetto "super".
* Factory Method Pattern: c'è un Costruttore che contiene tutti i metodi per manipolare l'oggetto e ha il metodo astratto "factoryMethod()". - the dependency inversion principle permette di ridurre le dipendenze usando classi astratte. "Inversion" perché le dipendenze non sono top down, ma vanno tutte verso la classe astratta.
* Abstract Factory Pattern: fornisce un interfaccia con un metodo "create()" per ogni oggetto. Ogni create restituisce in interfaccia.
* Singleton Pattern: Ha solo una istanza, da cui si accede tramite il metodo statico "getInstance()". Il costruttore è privato.
* Command Pattern: Il cuore è l'interfaccia Command con execute() (e opzionalmente undo()). Quando si istanzia un comando, si passa come argomento un ricevitore. Nell'execute, non si fa altro che chiamare ricevitore.action(). La classe client si occuperà di istanziare sia i comandi che i ricevitori. - Gli ActionListener usano il Command Pattern.
* Object Adapter Pattern: Vogliamo adattare una classe (o interfaccia) A ad una interfaccia B. La classe B adapter implementa l'interfaccia B e contiene l'istanza della classe A.
* Facade Pattern: Fornisce un'interfaccia semplice per sistemi complessi. La classe ...Facade ha come parametri del costruttore le istanze dei sottocomponenti (non dovrebbe accedere a metodi dei componenti dei sottocomponenti).
* Template Pattern: Usato, ad esempio, per implementare un algoritmo. C'è una classe astratta che ha un metodo template() final che contiene le chiamate agli step dell'algoritmo. Alcuni sono metodi con body altri sono astratti. Alcuni sono metodi 'hook' perché hanno un body ma vuoto che se serve può venire sovrascritto. È uno dei più usati. Se erediti da una classe e sovrascrivi un metodo (o implementi un metodo astratto) stai utilizzando il template pattern.
* Iterator Pattern: Utilizza l'interfaccia Java Iterator. Si implementa una o più volte (ArrayList ha già il metodo iterator() che restituisce l'iteratore). Poi c'è l'interfaccia Aggregate con il metodo createIterator().
* Composite Pattern: È composto da una classe astratta o interfaccia "Component" che viene estesa da una classe leaf e composite. Permette di gestire gerarchicamente la struttura dati.
* State Pattern: Usato per implementare il comportamento di una macchina a stati. C'é l'interfaccia (o classe astratta State) che ha un metodo per funzionalità (o effetto). I costruttori delle classi che implementano State, possono prendere la classe Context che contiene tutti gli stati. In questo modo in ogni metodo, oltre che a eseguire l'effetto, può fare context.setCurrState(context.getXState()) oppure accedere a variabili del contesto. context.ExecuteEffect1() al suo interno non fa altro che chiamare currState.ExecuteEffect1()
* Proxy Pattern: Per accedere ad un oggetto che rappresenta l'oggetto originale. L'interfaccia "Subject" contiene i metodi principali. Poi c'è la classe che rappresenta il vero oggetto "RealSubject" e la classe "Proxy" che entrambe implementano l'interfaccia. Questo permette poi anche di sostituire la classe proxy con la vera classe. Il proxy può avere come componente la classe vera. Java RMI implementa un Remote Proxy Pattern, utilizzando un registro per saltare il servizio remoto che fornisce la risorsa.
* Model-View -Controller Pattern: è un pattern composto da Observer (per la parte Model), Strategy (per la parte Controller), e Composite (per la parte View) Patterns.