Programmation orientée objet
Classes et objets
On considère des rectangles dans le plan. Dans un premier temps, on suppose pour simplifier
que les côtés des rectangles sont parallèles aux axes. Un rectangle est donc complètement
déterminé par le point en bas et à gauche et par ses dimensions horizontale et verticale.
Exercice n° 1 (Rectangle)
Définir une classe Rectangle permettant de manipuler de tels objets. Définir trois
constructeurs prenant respectivement en paramètre 2 points, 1 points et 2 longueurs ou 4
longueurs.
Exercice n° 2
Écrire une méthode surface qui calcule la surface du rectangle. Écrire une méthode
translate qui déplace un rectangle en déplaçant le point en bas et à gauche. Que se passe-t-il
si plusieurs rectangles partagent le même point.
Exercice n° 3
Écrire une méthode contains qui teste si un point donné (en paramètre) est à l'intérieur du
rectangle. Écrire une autre méthode contains qui teste si un rectangle donné est à l'intérieur
du rectangle.
Exercice n° 4
Écrire une méthode sameAs qui teste l'égalité de deux rectangles.
Exercice n° 5
Ajouter à la classe Rectangle un attribut nbr qui comptabilise le nombre d'objets de la classe
Rectangle.
Exercice n° 6
Écrire une méthode hull qui calcule le rectangle englobant d'un ensemble de rectangles.
Cette méthode prend en paramètre un tableau de rectangles et retourne le plus petit rectangle
qui contient tous les rectangles du tableau.
On considère qu'un dessin est constitué d'un ensemble de rectangles.
Exercice n° 7 (Dessins)
Définir une classe Dessin. Chaque objet de cette classe contient un tableau de rectangles dont
la taille est fixée à la construction de l'objet. Au départ, un dessin ne contient aucun rectangle.
Écrire une méthode add qui permet d'ajouter un rectangle à un dessin.
Exercice n° 8
Écrire des méthodes surface et translate pour la classe Dessin. La surface d'un dessin est
la somme des surfaces de ses rectangles même si ceux-ci se superposent. Translater un dessin
consiste à translater chacun de ses rectangle.
Exercice n° 9
Ajouter à la classe Dessin une méthode hull qui calcule le rectangle englobant des
rectangles du dessin. Afin de pouvoir calculer de manière incrémentale ce rectangle
englobant, ajouter un attribut hullRect à la classe Dessin et modifier les méthodes pour
qu'elles prennent en compte cet attribut.
Héritage, masquage de méthode
On considère des rectangles donc les côtés ne sont plus nécessairement parallèles aux axes.
Un tel rectangle est vu comme un rectangle aux côtés parallèles qui aurait été incliné d'un
certain angle par rapport à l'horizontale.
Exercice n° 1
En utilisant l'héritage, définir une classe SlantedRectangle permettant de manipuler de tels
objets. Définir des constructeurs appropriés.
Exercice n° 2
Définir une méthode rotate dans l'esprit de la méthode translate.
Exercice n° 3
De quelles méthodes hérite la classe SlantedRectangle ? Redéfinir celles qui le nécessitent.
Exercice n° 4
Pour chacun des appels de méthode ci-dessous, dire s'il va être compilé correctement et
auquel cas, quelle méthode est appelée effectivement à l'exécution ?
Point p = new Point(1,2);
Rectangle r = new Rectangle(p, 2, 3);
Rectangle t = new SlantedRectangle(p, 2, 3);
SlantedRectangle s = new SlantedRectangle(p, 2, 3);
[Link]([Link]());
[Link](2);
[Link]([Link](p));
[Link]([Link]());
[Link](2);
[Link]([Link](p));
[Link]([Link]());
[Link](2);
[Link]([Link](p));
Exercice n° 5
Est-ce que la classe Dessin définie précédemment peut contenir des rectangle inclinés ? Est-
ce que les méthodes surface, contains et hull de la classe Dessin fonctionnent encore
correctement ?
Exercice n° 6
Définir une méthode String toString() dans la classe Rectangle ? Est-ce en fait une
définition ou une redéfinition ? Est-il nécessaire de la redéfinir dans la classe
SlantedRectangle ?
Exercice n° 7
Redéfinir la méthode equals dans les classes Rectangle et SlantedRectangle.
On considère les définitions de classes suivantes
class A {
void f(A o) {
[Link]("void f(A o) dans A");
}
}
class B extends A {
void f(A o) {
[Link]("void f(A o) dans B");
}
}
Exercice n° 8
Qu'affiche le fragment de programme suivant ?
A a = new A();
A ab = new B();
B b = new B();
a.f(a);
a.f(ab);
a.f(b);
ab.f(a);
ab.f(ab);
ab.f(b);
b.f(a);
b.f(ab);
b.f(b);
Exercice n° 9
On ajoute maintenant à la classe B la méthode suivante
void f(B o) {
[Link]("void f(B o) dans B");
}
Est-ce une redéfinition ou une surcharge ? Qu'affiche alors le fragment de programme de
l'exercice 8 ?
Exercice n° 10
On ajoute finalement à la classe A la méthode suivante
void f(B o) {
[Link]("void f(B o) dans A");
}
Est-ce une redéfinition ou une surcharge ? Qu'affiche alors le fragment de programme de
l'exercice 8 ?
Exercice n° 11
Qu'affiche le fragment de programme suivant ?
[Link](a instanceof A);
[Link](ab instanceof A);
[Link](b instanceof A);
[Link](a instanceof B);
[Link](ab instanceof B);
[Link](b instanceof B);
Exercice n° 12
Dans la classe Rectangle a été définie une méthode boolean contains(Rectangle). Cette
méthode doit-elle être redéfinie dans la classe SlantedRectangle ? Quels cas ne sont pas
couverts par cette redéfinition ? On ajoute alors une méthode boolean
contains(SlantedRectangle) dans les classes Rectangle et SlantedRectangle. Quels
cas ne sont toujours pas couverts par ces ajouts ?
Exercice n° 13
On considère les définitions de classes suivantes
class C {
char ch = 'C';
char getCh() { return ch; }
}
class D extends C {
char ch = 'D';
char getCh() { return ch; }
}
Qu'affiche le fragment de programme suivant ?
C c = new C();
C cd = new D();
D d = new D();
[Link]([Link]);
[Link]([Link]());
[Link]([Link]);
[Link]([Link]());
[Link]([Link]);
[Link]([Link]());
Interfaces et classes abstraites
1 Figures
En plus des points et des rectangles vus au séances précédentes, on s'intéresse maintenant aux
disques. On considère qu'un disque est déterminé par son centre et son rayon.
Exercice n° 1
Définir une classe Disque avec des constructeurs appropriés ainsi que des méthodes
translate, surface et contains.
Aux séances précédentes avait été définie une classe Dessin qui permettait de regrouper des
rectangles.
Exercice n° 2
Quelle est la bonne méthode pour avoir des dessins capables de regrouper à la fois des
rectangles et des disques. On pourra utiliser une interface Figure.
Exercice n° 3
La classe Dessin possède des méthodes translate, surface et contains. Peut-elle
implémenter l'interface Figure ? Quel est l'intérêt de faire cela ?
2 Expressions arithmétiques
On considère maintenant des expressions arithmétiques formées à partir de constantes réelles
(nombres flottants) et utilisant les quatre opérations arithmétiques usuelles (addition,
soustraction, multiplication et division). Un telle expression est par exemple 3 + (4.7 + 2.3) *
5.
Ces expressions arithmétiques sont représentés par des arbres binaires. Les nœuds internes de
l'arbre contiennent les opérateurs alors que Les feuilles de l'arbre contiennent les constantes.
Les fils gauche et droit d'un nœud interne représentent les deux sous-expressions gauche et
droite. L'expression 3 + (4.7 + 2.3) * 5 par l'arbre de la figure ci-dessous.
FIG 1. L'arbre de l'expression 3 + (4.7 + 2.3) * 5
L'organisation en interfaces et classes
Exercice n° 4
Définir une interface ArithExpr qui déclare les fonctionnalités d'une expression arithmétique.
La seule fonctionnalité requise est de pouvoir être évaluée. Déclarer en conséquence une
méthode eval du bon type.
Pour représenter l'expression, on va créer des objets pour chacun des nœuds. Ces objets vont
bien sûr être des instances de classes différentes suivant qu'il s'agisse de nœuds internes ou de
feuilles.
Exercice n° 5
Définir une classe Constant pour représenter les constantes des expressions.
Exercice n° 6
Définir quatre classes Addition, Soustraction, Multiplication et Division pour les
opérations arithmétique. On remarque que ces quatre classes partagent beaucoup de
propriétés. Comment faut-il faire pour partager le code ?
Exercice n° 7
Redéfinir la méthode toString afin d'afficher les expressions en notation infixe. Écrire des
méthodes prefix et suffix permettant d'afficher les expressions en notation préfixe et
suffixe.
Exercice n° 8
Que faut-il ajouter pour que les expressions arithmétiques puissent contenir des variables
comme dans l'expression 3 * x + 7 ? Comment définir la méthode eval pour une variable ?
Parseurs
La lecture d'une expression arithmétique se fait par l'intermédiaire d'un parseur. Un parseur
est un objet capable de créer une expression arithmétique à partir d'une chaîne de caractères.
Exercice n° 9
Définir une classe abstraite ArithExprParser ayant deux méthodes parse. La première
méthode prend en paramètre une chaîne de caractères alors que la seconde prend un Reader.
Exercice n° 10
Écrire une classe PrefixParser permettant de lire une expression arithmétique en notation
préfixe.
Exercice n° 11 (difficile)
Écrire une classe InfixParser permettant de lire une expression arithmétique en notation
infixe.