Éditer sur GitHub

TP - Mise en oeuvre des patrons de conception avec des classes géométriques

Introduction

L'objectif de ce TP est de s'exercer à mettre en oeuvre des patrons de conception via la création d'une petite bibliothèque de manipulation des géométries OGC :

Géométrie OGC

Vous noterez toutefois que ceci n'est qu'un exercice :

Démarrage

Mise en garde

Vous devrez impérativement :

Pour ce faire, il vous est vivement conseillé de :


0.1 - Geometry, Point et LineString

Objectif : Préparation du TP, utilisation d'interface, encapsulation

Implémenter les trois classes suivantes illustrées sur le schémas ci-après :

Schéma UML

Remarques :

0.2 - Geometry.isEmpty()

Objectif : Bonne pratique NonNullObject

Afin d'éviter d'avoir à tester des coordinates ou points null ou undefined, nous allons ajouter le concept de géométrie vide :

Schéma UML

Remarque : Nous ne traiterons pas le cas d'un appel new LineString(points) avec un point null.

0.3 - Geometry.translate(dx,dy)

Objectif : Exploiter une interface pour réaliser un traitement spécifique

Ajouter une méthode de permettant de translater une géométrie.

Schéma UML

0.4 - Geometry.clone()

Objectif : Patron de conception Prototype

En introduisant la fonction précédente, nous avons renoncé à l'idée d'avoir des géométries immuable (non modifiable après construction).

Nous allons donc ajouter une méthode clone() permettant de récupérer une copie d'une géométrie :

Schéma UML

Exemple d'utilisation :

const copy = g.clone();
copy.translate(10.0,10.0);
//... "g" n'est pas modifiée

Remarques :

0.5 - Envelope et EnvelopeBuilder

Objectif : Patron de conception Builder

Nous souhaitons calculer l'emprise d'une géométrie (la bbox). La logique de calcul de min/max en oeuvre étant assez complexe, nous ne souhaitons pas l'implémenter dans les classes Point et LineString.

Nous allons donc procéder comme suit :

Schéma UML

Exemple d'utilisation :

const builder = new EnvelopeBuilder();
builder.insert([0.0,1.0]);
builder.insert([2.0,0.0]);
builder.insert([1.0,3.0]);
// récupération du résultat
const result = builder.build();

Remarques :

0.6 - Geometry.getEnvelope() : Envelope

Objectif : Facade sur EnvelopeBuilder

Ajouter une méthode utilitaire sur Geometry pour récupérer facilement l'enveloppe comme suit :

Schéma UML

0.7 - WktWriter

Objectif : Mesurer l'intérêt d'une conception propre et de GeometryVisitor dans les questions suivantes

Ajouter une classe WktWriter avec une méthode permettant de convertir une géométrie au format WKT qui prendra par exemple les formes suivantes :

POINT EMPTY
POINT(3.0 4.0)
LINESTRING EMPTY
LINESTRING(0.0 0.0,1.0 1.0,5.0 5.0)

Schéma UML

Exemple d'utilisation :

const g = new Point([3.0,4.0]);
const writer = new WktWriter();
// "POINT(3.0 4.0)"
const wkt = writer.write(g);

Remarques :

if ( geometry instanceof Point ){
    // traiter le cas Point
}else if ( geometry instanceof LineString ){
    // traiter le cas LineString
}else{
    throw new TypeError("geometry type not supported");
}

0.8 - GeometryVisitor

Objectif : Patron de conception Visitor, prise en main

Schéma UML

Exemple d'utilisation :

const visitor = new LogGeometryVisitor();
const geometry = new Point([3.0,4.0]);
geometry.accept(visitor);

Remarque : pour les tests, vous pourrez remplacer temporairement console.log par une fonction vous permettant de capturer le résultat.

0.9 - WktVisitor

Objectif : Patron de conception Visitor, mise en oeuvre dans un cas concret

Reprendre l'implémentation de WktWriter sous la forme d'un GeometryVisitor en implémentant une classe WktVisitor.

Schéma UML

Exemple d'utilisation :

const visitor = new WktVisitor();
const geometry = new Point([3.0,4.0]);
geometry.accept(visitor);
// "POINT(3.0 4.0)"
const wkt = visitor.getResult();

0.10 - Geometry.asText()

Objectif : Patron de conception Facade, héritage à trois niveau avec interface et abstract.

A l'aide de AbstractGeometry et WktVisitor :

Schéma UML

0.11 - EnvelopeBuilder en tant que GeometryVisitor

Objectif : Visitor, refactoring (extraction de l'implémentation d'une fonctionnalité)

Schéma UML

0.12 - GeometryWithCachedEnvelope

Objectif : Patron de conception Decorator

Schéma UML

Exemple d'utilisation :

const g = new Point([3.0,3.0]);
// décoration
g = new GeometryWithCachedEnvelope(g);
const a = g.getEnvelope() ; // calcul et stockage dans cachedEnvelope
const b = g.getEnvelope() ; // renvoi de cachedEnvelope
// a et b sont la même instance

Remarque : Nous invaliderons ce cache dans translate(dx,dy).

0.13 - GeometryCollection

Objectif : Patron de conception Composite, Refactoring

Ajouter une classe GeometryCollection représentant une géométrie multiple, adapter les autres fonctionnalités.

Schéma UML

Remarque : Le format WKT prendra la forme suivante pour les GeometryCollection :

GEOMETRYCOLLECTION EMPTY
GEOMETRYCOLLECTION(POINT(3.0 4.0),LINESTRING(0.0 0.0,1.0 1.0,5.0 5.0))

0.14 - GeometryVisitor renvoyant un résultat

Objectif : Exploiter les classes génériques, adapter le patron visiteur au contexte.

Pour avoir la capacité de renvoyer des résultats avec des types variables :

const visitor = new LengthVisitor();
const result = geometry.accept(visitor);