HeadFirst Mix patterns

Cette page liste les exemples impliquant plusieurs patterns dans le livre "Head First Design Patterns".

Qui fait quoi ?

Qui fait quoi ?

Chapter 9 - The Iterator and Composite Patterns: Well-Managed Collections

p 315 de la version papier

Exemple non traité ; table des matières :
Breaking News: Objectville Diner and Objectville Pancake House Merge
Check out the Menu Items
Lou and Mel’s Menu implementations
What’s the problem with having two different menu representations?
What now?
Can we encapsulate the iteration?
Meet the Iterator Pattern
Adding an Iterator to DinerMenu
Reworking the Diner Menu with Iterator
Fixing up the Waitress code
Testing our code
What have we done so far?
What we have so far...
Making some improvements...
Cleaning things up with java.util.Iterator
We are almost there...
What does this get us?
Iterator Pattern defined
Single Responsibility
Taking a look at the Café Menu
Reworking the Café Menu code
Adding the Café Menu to the Waitress
Breakfast, lunch AND dinner
What did we do?
We decoupled the Waitress....
... and we made the Waitress more extensible
But there’s more!
Iterators and Collections
Is the Waitress ready for prime time?
Just when we thought it was safe...
What do we need?
The Composite Pattern defined
Designing Menus with Composite
Implementing the Menu Component
Implementing the Menu Item
Implementing the Composite Menu
Getting ready for a test drive...
Now for the test drive...
Getting ready for a test drive...
Flashback to Iterator
The Composite Iterator
The Null Iterator
Give me the vegetarian menu
The magic of Iterator & Composite together...
Tools for your Design Toolbox

Simulateur de canards

p 499 de la version papier (chapitre 12)

On réalise un simulateur de canards pour un parc naturel.
Le client est un quackologue, qui voudrait pouvoir simuler et suivre des populations de canards.

On va répondre aux différentes demandes en utilisant des patterns, mais il ne s'agit pas de patterns composés, au sens MVC par exemple.
Ici, il s'agit plutôt de patterns qui fonctionnent ensemble.

1 - Au départ

On démarre l'application avec :
Récupérer, lire, compiler et exécuter le code de départ dans ce répertoire.
Dans la classe DuckSimulator, à quel endroit le polymorphisme est-il utilisé ? De quel type de polymorphisme s'agit-il ?

2 - Et les oies

On veut pouvoir gérer les oies (= goose en anglais) dans notre simulateur ; on nous fournit une classe :
public class Goose {
    public void honk() {
        System.out.println("Honk");
    }
}
La demande est de pouvoir utiliser des oies partout où on utilise des canards.
Y a-t-il un pattern adapté à cette demande ?
Ecrivez le code permettant de rajouter les oies dans notre simulateur.

3 - Comptage

Le client souhaite pouvoir compter le nombre de quacks effectués par l'ensemble des canards observés.
Mais il ne veut pas compter les quacks des oies.
L'output souhaité est le suivant :
=== Duck Simulator ===
Mallard Quack
Redhead Quack
DuckCall quack
RubberDuck quack
Honk

Number of quacks : 4
Comment rajouter ce comportement sans avoir à modifier toutes les classes de canards ?
Modifier le code pour obtenir l'output souhaité.

4 - Avec ou sans comptage ?

Cette solution fonctionne, mais les risques d'erreurs sont importants, car il faut décorer chaque canard créé.
De plus, le client veut parfois utiliser le simulateur avec comptage, et parfois sans le comptage.
Ecrire une solution permettant facilement soit de créer des canards avec comptage, soit sans comptage.
Tous les canards créés doivent avoir le même comportement : avec comptage ou sans comptage.
Les quacks des oies ne sont toujours pas comptés.

Modifier la fonction main() de manière à pouvoir lui passer un paramètre qui peut prendre les valeurs "count" ou "normal".
java Main normal

=== Duck Simulator ===
Mallard Quack
Redhead Quack
DuckCall quack
RubberDuck quack
Honk
    
java Main count

=== Duck Simulator ===
Mallard Quack
Redhead Quack
DuckCall quack
RubberDuck quack
Honk

Number of quacks : 4
    

5 - Flock

flock = troupe, foule
Maintenant qu'on sait observer les canards, on aimerait bien gérer les différents groupes de canards qui peuplent le parc.
Ce qu'il nous faudrait, c'est la possibilité de gérer des collections et sous-collections de canards ; pouvoir appliquer des opérations sur des groupes entiers.

On créé une classe Flock, représentant un groupe de canards.
On va faire un choix d'implémentation : les méthodes concernant la gestion des enfants ne seront présentes que dans Flock.
Dans DuckSimulator::simulate(), on crée 3 groupes :
- un groupe contenant les 5 canards et oies déjà créés.
- un groupe contenant 4 nouveaux canards mallards.
- Un groupe contenant tous les canards (contenant donc les deux groupes précédemment créés).
        Flock f1 = new Flock();
        f1.addChild(mallardDuck);
        f1.addChild(redheadDuck);
        f1.addChild(duckCall);
        f1.addChild(rubberDuck);
        f1.addChild(goose);

        Quackable m1 = factory.createMallardDuck();
        Quackable m2 = factory.createMallardDuck();
        Quackable m3 = factory.createMallardDuck();
        Quackable m4 = factory.createMallardDuck();
        
        Flock f2 = new Flock();
        f2.addChild(m1);
        f2.addChild(m2);
        f2.addChild(m3);
        f2.addChild(m4);
        
        Flock f3 = new Flock();
        f3.addChild(f1);
        f3.addChild(f2);

Complétez le code pour obtenir cet output :
java Main count

=== Duck Simulator ===

Duck Simulator: Whole flock simulation
Mallard Quack
Redhead Quack
DuckCall quack
RubberDuck quack
Honk
Mallard Quack
Mallard Quack
Mallard Quack
Mallard Quack

Duck Simulator: Mallard flock simulation
Mallard Quack
Mallard Quack
Mallard Quack
Mallard Quack

The ducks quacked : 12 times

6 - Tracking individual ducks

Maintenant, le quackologiste veut pouvoir suivre certains individus en particulier (afficher leurs quacks).
En d'autres termes, il veut pouvoir observer certains canards, ce qui mène au pattern Observer.

Les canards sont les observables. Pour que le pattern Observer fonctionne, ils doivent tous dériver d'une abstraction qui a besoin de 2 méthodes : registerObserver() et notifyObservers().

Les default methods permettent de mettre ces 2 méthodes directement dans Quackable.

Pour que chaque canard implémente cette interface, il faut que chaque classe implémente la gestion d'une liste d'observateurs et de notification, ce qui entraîne des répétitions de code.
Pour limiter ces répétitions, on a plusieurs solutions :
  1. On peut écrire une classe ObservableHelper implémentant ce mécanisme, et utiliser la composition dans les classes de canards :
    import java.util.Iterator;
    import java.util.ArrayList;
    
    public class ObservableHelper implements Quackable {
        ArrayList<Observer> observers = new ArrayList<Observer>();
        Quackable duck;
     
        public ObservableHelper(Quackable duck) {
            this.duck = duck;
        }
      
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
      
        public void notifyObservers() {
            Iterator<Observer> iterator = observers.iterator();
            while (iterator.hasNext()) {
                Observer observer = iterator.next();
                observer.update(duck);
            }
        }
     
        public Iterator<Observer> getObservers() {
            return observers.iterator();
        }
    }
    
    On est toujours obligés de modifier chaque classe de canard :
    public class RubberDuck implements Quackable {
        ObservableHelper observable;
    
        public RubberDuck() {
            observable = new ObservableHelper(this);
        }
     
        public void quack() {
            System.out.println("Squeak");
            notifyObservers();
        }
    
        public void registerObserver(Observer observer) {
            observable.registerObserver(observer);
        }
    
        public void notifyObservers() {
            observable.notifyObservers();
        }
      
        public String toString() {
            return "Rubber Duck";
        }
    }
    
  2. On peut utiliser l'héritage, en écrivant une classe Observable, qui implémente Quackable et qui contient le mécanisme. Les classes de canards dériveront de Observable.
    import java.util.Iterator;
    import java.util.List;
    import java.util.ArrayList;
    
    public abstract class Observable implements Quackable{
        
        ArrayList observers = new ArrayList();
    
        public void quack(){
            notifyObservers();
        }
        
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
      
        public void notifyObservers() {
            Iterator iterator = observers.iterator();
            while (iterator.hasNext()) {
                Observer observer = iterator.next();
                observer.update(this);
            }
        }
     
        public Iterator getObservers() {
            return observers.iterator();
        }
    }
    
    Et il faut adapter les classes de canards :
    public class RedheadDuck extends Observable {
        public void quack() {
            System.out.println("Redhead Quack");
            super.quack();
        }
    }
    
Noter que dans les deux cas, on doit modifier les classes de canards. Attention à l'implémentation de l'oie et de Flock.

On crée aussi une classe d'observateur que l'on appelle Quackologist, qui n'a besoin que d'une méthode update().

Dans main(), on a juste à ajouter :
Quackologist quackologist = new Quackologist();
f3.registerObserver(quackologist);
Implémenter de manière à avoir l'output suivant :
java Main count

=== Duck Simulator ===
Mallard Quack
Quackologist: Mallard Duck just quacked.
Redhead Quack
Quackologist: Redhead Duck just quacked.
DuckCall quack
Quackologist: Duck Call just quacked.
RubberDuck quack
Quackologist: Rubber Duck just quacked.
Honk
Quackologist: Goose pretending to be a Duck just quacked.
Mallard Quack
Quackologist: Mallard Duck just quacked.
Mallard Quack
Quackologist: Mallard Duck just quacked.
Mallard Quack
Quackologist: Mallard Duck just quacked.
Mallard Quack
Quackologist: Mallard Duck just quacked.

The ducks quacked : 8 times

7 - Représenter les canards

(pas présent dans le livre Head First)

Voir la page sur Flyweight.

MVC

Voir la page sur le MVC.