Sort

Cet exemple montre plusieurs versions successives d'un logiciel. Ces différentes versions permettent d'illustrer certains concepts parmi lesquels

Version 1.0

Il s'agit d'écrire une application qui permette d'exécuter un tri sur un jeu de données et de visualiser les différentes actions de ce tri sur la sortie standard. L'interface Sort décrit un tri comme étant une classe implémentant une méthode doSort(SortableData).
L'interface SortableData décrit une collection triable. Une telle collection doit implémenter quatre méthodes QuickSort et InsertionSort sont deux implémentations de Sort. Ce sont toutes les deux des singletons, puiqu'il n'y a aucune raison de créer deux instances d'un même algorithme de tri.
SortableArray est une implémentation de SortableData, créée à partir d'un tableau. Le tableau passé en paramètre du constructeur sera trié par l'application de Sort.doSort(SortableData) au SortableArray obtenu.
SortableDataTracer et SortableDataStatistic sont deux décorateurs de SortableData qui permettent respectivement l'affichage des actions effectuées par le tri sur la sortie standard, et le calcul de statistiques sur le tri (nombre d'accès, de comparaisons et d'échanges).

Version 2.0

L'amélioration consiste à doubler la visualisation sur la sortie standard par une visualisation graphique. Les modifications de InsertionSort et QuickSort se situent uniquement au niveau du main(String []) pour prendre en compte le passage de SortableDataTracer en Observable, avec comme observateurs un AsciiTracer et un WinTracer. De plus, les main(String []) se terminent par l'instruction System.exit(0); pour quitter l'application. Sinon, celle-ci continue car le fait d'utiliser un composant graphique a lancé un thread pour la gestion des événements.
La classe SortableDataTracer a été profondemment modifiée puisqu'elle étend désormais java.util.Observable et ne fait plus d'affichage elle-même, mais prévient des traceurs (implémentant java.util.Observer).
Les classes InsertionSort, QuickSort, Sort, SortableArray, SortableData, SortableDataStatistic n'ont pas été modifiées.
Les classes AsciiTracer et WinTracer implémentent toutes les deux un Observer permettant une double visualisation du déroulement du tri par une interface graphique (WinTracer) et sur la sortie standard (AsciiTracer).

Version 2.1

Une légère amélioration peut être apportée à WinTracer en remplaçant la boucle de temporisation
    for (int i = 0; i < slider.getValue() * 100000; i++)
        ;
par les instructions
    try {
        Thread.currentThread().sleep(50 * slider.getValue());
    } catch (InterruptedException e) {
    }
qui rende la temporisation indépendante de la machine utilisée.

Version 3.0

Cette version a pour but de ne plus obliger à écrire un main(String []) pour chaque nouveau tri. Le nom du tri sera passé comme paramètre de la ligne de commande. Les modifications de InsertionSort et QuickSort se situent uniquement dans l'ajout d'une méthode de classe getInstance() qui renvoie une instance de la classe.  Les méthodes main(String []) de ces deux classes ne sont plus indispensables, mais restent utilisables.
Les classes AsciiTracer, Sort, SortableArray, SortableData, SortableDataStatistic, SortableDataTracer, WinTracer n'ont pas été modifiées.
Les classes SortFactory, SortNotFoundException et TestSort ont été rajoutées.
La classe SortFactory est une fabrique qui ne contient que des méthodes de classe. Elle renvoie une instance d'un tri, soit par l'appel d'une méthode spécifique au tri désiré, soit par le passage d'un mot clé. Si le mot-clé ne convient pas, une exception SortNotFoundException est levée. A noter qu'il s'agit à nouveau d'un singleton. Mais cette fois, contrairement à QuickSort et InsertionSort, aucune instance n'est créée. L'unicité vient du fait que la classe ne possède aucune méthode d'instance.
La classe TestSort sert de support à la méthode main(String []) utilisée pour lancer l'application.

Version 3.1

Plutôt que d'utiliser une fabrique, on utilise dans cette version le chargement dynamique de classe. Donc au lieu de passer un mot-clé pour désigner un tri, on passe directement le nom de la classe qui l'implémente. Les classes SortFactory et SortNotFoundException sont désormais inutiles.
La méthode main(String []) de la classe TestSort a été modifiée pour effectuer le chargement dynamique plutôt que d'utiliser SortFactory.

Version 3.99

Il s'agit en fait d'une version préliminaire à la version 4.0. Il est possible dans cette version d'exécuter plusieurs méthodes de tris sur un même jeu de données dans un seul appel. Toutefois, ces tris ne sont pas exécutés en parallèle, mais l'un après l'autre. Pour cela, les instances de WinTracer sont désormais de simples JPanel et non plus des JFrame et ne contiennent plus que la représentation des données. Il est donc necessaire à la création d'un WinTracer de lui passer en paramètre le JSlider qui gère la durée de la temporisation.
C'est la classe TestSort qui a maintenant en charge la création d'une fenêtre principale, à laquelle on associe un WindowListener permettant la sortie de l'application quand la fenêtre est fermée. A noter l'utilisation des exceptions pour différencier dans la ligne de commande les classes de tri à charger des données à trier.
Les méthodes main(String []) de InsertionSort et QuickSort n'étant plus compatibles avec la nouvelle version de WinTracer, elles ont été supprimées.

Version 4.0

Cette version est similaire à la version 3.99, mais les tris sont cette fois exécutés en parallèle. Pour cela, on utilise les threads.