interface et classe ift1025, programmation 2 jian-yun nie
TRANSCRIPT
Interface et Classe
IFT1025, Programmation 2
Jian-Yun Nie
Concepts importants
• Interface: un contrat qu’une classe doit se conformer– Favorise la réutilisation des codes– Il suffit de savoir qu’une classe se conforme à une
interface pour pouvoir l’utiliser (sans connaître les détails de son implantation)
• Classe normale: une classe implantée (dont les méthodes sont toutes définies)
• Classe abstraite: une classe qui n’est pas complètement implantée– Mi-chemin entre classe normale et interface
Utilisation des classe
• Soit la classe BankAccount et les sous-classes CheckingAccount et SavingsAccount
• On peut faire des opérations en commun sur l’ensemble d’objets de la classe BankAccount (y compris ceux des sous-classe),
• Principe:– Pour tout objet ref de BankAccount:
• ref.operation– Conditions:
• operation est définie pour la classe mère (pour que ref.operation ne gégère pas une erreur de compilation)
• Operation est héritée ou redéfinie dans les sous-classes (polymorphisme)
• Polymorphisme assure qu’on utilise la version de l’instance
Exemple trivial: trouver balance maxpublic BankAccount maxAccount(BankAccount [] compte){
BankAccount ref, refMax;int i;double max = 0;for (i=0; i<compte.length; i++){
ref = compte[i];if (ref.getBalance() > max) {
max = ref.getBalance(); refMax=ref;
}}return refMax;
}
• C’est possible grâce à getBalance() dans la classe BankAccount (et héritée dans les sous-classes)
Utilisation:BankAcount meilleurClient;BankAccount [] clients = {new BankAccount(100), new CheckingAccount(10), //Petit tableau de 3 éléments
new SavingsAccount(0.05)}… // des manipulations sur ces comptesmeilleirClient = maxAccount(clients);
• Avantage de l’héritage et l’homogénéité dans une classe
Cas non trivial
• On ne peut pas implanter une méthode pour la classe mère, mais seulement dans les sous-classes
• Exemple:– Classe: Forme: draw() non implantables– Sous-classes: Rectangle: draw() implanté
Rond: draw() implantée
• Mais on veut quand même utiliser la référence ref de classe Forme pour ref.draw()
Généralisation
• On veut créer des opérations applicables pour toutes les instances d’une classe
• Si une méthode est implantée pour la classe mère et toutes les sous-classe (héritée ou redéfinie)– Cas trivial: la méthode est applicable
• Deux cas non triviaux:1. La méthode ne peut pas être implantée pour la
classe mère, mais elle le peut pour les sous-classes
2. On désire appeler la même méthode pour différentes classes (non reliées)
Premier cas: classe abstraite• On veut définir une classe correspondant un
concept (abstraite) englobant toutes les formes (rectangle, triangle, etc.)
• On sait que chaque forme a une surface• On souhaite définir une méthode getSurface
pour chaque forme • Problème:
– Il existe pas une façon générale pour calculer la surface pour une forme
– Le calcul est possible seulement pour les sous-classes (Rectangle, Triangle, Rond, etc.)
Hiérarchie
Forme: getSurface()
Rectangle Triangle Rond …
getSurface() getSurface() getSurface()
• On ne veut pas créer une instance de Forme• Solution: classe abstraite pour la classe mère
Non implantable
Deuxième cas
• On veut pouvoir appliquer une opération sur des objets– Ex: comparer les objets de la même classe pour
connaître un ordre: <, >, etc.
• Cette comparaison doit s’appliquer sur des classes très différentes– BankAccount, Rectangle, etc. avec des critères
différents
• Impossible d’utiliser classes abstraite pour ce cas– Les classe ne sont pas sous la même classe mère
Illustration
Object
BankAccount Mot Personne Forme
CheckingAccount Rectangle Triangle Rond
SavingsAccount
Classes pour lesquelles on veut définir l’ordre• Impossible de regrouper les classes sous une autre classe mère
– Héritage simple
• Solution: interface
Ordre
Classe abstraite
• Déclarationabstract public class Nom { … }
• Exempleabstract class Forme
{
int x, y; // coordonnée du début de la forme
abstract float getSurface();
}
Caractéristiques de classe abstraite
• Déclaration de classe avec abstract• Dans le corps {…}:
– On peut définir une méthode abstraite• abstract float getSurface();• Méthode abstraite n’a pas de corps (non implantée)
– Mais une classe abstraite peut ne pas avoir de méthode abstraite
– On peut déclarer des attributs et implanter des méthodes
• On ne peut pas créer d’instance d’une classe abstraite– new Forme(): Erreur de compilation
Sous-classes d’une classe abstraite
• class SousClasse extends Classe
• Si une sous-classe n’est pas abstraite– Toutes les méthodes abstraites héritées
doivent être implantées (avec un corps)– Sinon, la sous-classe doit aussi être abstraite
• Instance possible pour une sous-classe non abstraite
Exempleabstract class Forme
{int x, y; // coordonnée repère de la formeabstract float getSurface();abstract void draw();
}
public class Rectangle extends Forme{
int longueur, largeur;public float getSurface(){
return (float) longueur * largeur;}public void draw(){ … // dessiner le rectangle}
}
• Une sous-classe concrète doit implanter toutes les méthodes abstraites héritées
Exemple (cont.)public class Rond extends Forme{
int rayon;public float getSurface(){
…}
}
// Une forme composée de deux autres formesabstract class FormeComposee extends Forme{
Forme f1, f2;}
• Si une sous-classe n’implante pas toutes les méthodes abstraite, elle continue à être abstract
Hérités:int x, y; abstract float getSurface();abstract void draw();
Interface• Interface = contrat = exigence de certains types
de comportements• Exigences applicables sur des classes
différentes: BankAccount, Mot, …– Exemple: ordonner les objets
• BankAccount: selon la balance• Mot: selon l’ordre de mot, …
• Si on utilise seulement classe (abstraite):– On doit définir ces comportements séparément dans
chaque classe – Pas moyen de regrouper ces objets
Utilisation désirée (exemple)
• Pour un groupe d’objets avec un comportement commun: ordre(Objet)– Faire le même traitement de tri– Programme général qui fonctionne sur tous les objets
possédant ordre(Objet)• Pour tous ref1 et ref2 de ce type
– ref1.ordre(ref2) >0, ref1.ordre(ref2) =0, ref1.ordre(ref2) <0
– Réordonner selon leur comparaison
– Ce programme ne doit pas seulement fonctionner pour une classe
– Solution: interface
interface
• Une interface permet de regrouper les objets qui peuvent manifester le même type de comportement (mêmes méthodes)
• Interface n’a pas la même contrainte de héritage simple pour les classe– Une classe peut se conformer à plusieurs interfaces– Ex:
• Mot peut se comparer par ordre(…) et peut être mesuré en longueur, etc.
• Interface 1 pour ordre, interface 2 pour longueur, …
Définition d’une interface
• public interface Measurable
{
double getMeasure();
} • Lister toutes les méthodes (comportements)
désirées sans implantation (juste la signature)– Méthodes sont automatiquement abstract et public
• Pas d’attribut (sauf constante)
Utiliser une interface
• Une classe se conforme à une interface:– class BankAccount implements Measurable
{ …public double getMeasure() {
return value; }
• La classe doit implanter toutes les méthodes exigées par l’interface
Utiliser une interface
• Une autre classe peut se conformer à la même interface• public class Coin implements Measurable
{ public double getMeasure() {
return value; } . . .
} • Mécanisme similaire à un héritage multiple, mais
différent
Utiliser une interface• On peut utiliser une interface comme un type• Ex: déterminer le max et la somme:public class DataSet { . . .
public void add(Measurable x) {
sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure())
maximum = x; count++; } public Measurable getMaximum() {
return maximum; } private double sum; private Measurable maximum; private int count;
}
x est du type Measurable:- possède getMeasure()
Utiliser une interface• 01: /**• 02: This program tests the DataSet class.• 03: */• 04: public class DataSetTester• 05: {• 06: public static void main(String[] args)• 07: {• 08: DataSet bankData = new DataSet();• 09: • 10: bankData.add(new BankAccount(0));• 11: bankData.add(new BankAccount(10000));• 12: bankData.add(new BankAccount(2000));• 13: • 14: System.out.println("Average balance = " • 15: + bankData.getAverage());• 16: Measurable max = bankData.getMaximum();• 17: System.out.println("Highest balance = " • 18: + max.getMeasure());• 19: • 20: DataSet coinData = new DataSet();• 21: • 22: coinData.add(new Coin(0.25, "quarter"));• 23: coinData.add(new Coin(0.1, "dime"));• 24: coinData.add(new Coin(0.05, "nickel"));• 25: • 26: System.out.println("Average coin value = " • 27: + coinData.getAverage());• 28: max = coinData.getMaximum();• 29: System.out.println("Highest coin value = " • 30: + max.getMeasure());• 31: }• 32: }
Average balance = 4000.0 Highest balance = 10000.0 Average coin value = 0.13333333333333333 Highest coin value = 0.25
Relation entre classe et interface
class BankAccount implements Measuarable• Convertir le type d’une classe à une interface
– BankAccount account = new BankAccount(10000);Measurable x = account; // OK System.out.println(x.getMeasure());
• Casting une référence du type interface en une classe– Ajouter un objet à DataSet
DataSet coinData = new DataSet();coinData.add(new Coin(0.25, "quarter"));coinData.add(new Coin(0.1, "dime"));. . .Measurable max = coinData.getMaximum(); // Get the largest coin
– String name = max.getName(); // ERROR – Coin maxCoin = (Coin) max;
String name = maxCoin.getName(); // OK
Utilisation d’interface générale
• Interface comme un type abstrait de données– Liste– Arbre binaire– …
• Chaque type abstrait possède des méthodes « standard »
• Interface: exiger ces méthodes
Classe abstraite vs. Interface• Classe abstraite
– Certaines méthodes peuvent être abstraites– Peut contenir des attributs– Peut implanter des méthodes– Héritage simple
• Interface = contrat– Aucune implantation de méthode– Différentes classes peuvent signer le même contrat
• Classe = famille – posséder le même nom de famille– a la même habileté (peut être une méthode abstraite)
• Interface = contrat– Contrat commun pour différentes familles
Exemple: Interface Movable
Movable
Potion
«interface»
SwordRing
Gnomemoves
Interface Weapon
Weapon
Pen
«interface»
MissileLauncherSword
Explorerwields
“Héritage” Multiple d’interfaces par une classe
Weapon
«interface»
Sword
Movable
«interface»
class Sword implements Weapon, Movable {…}
Extension d’interface• Assume all weapons are movable:
Weapon
Pen
«interface»
MissleLauncherSword
Movable
Potion
«interface»
Ring
interface Weapon extends Movable {…}
Interface
Modifier une interface?
• Si une classe définie n’est plus suffisante– Ajouter des attributs et des méthodes– Les autres classes utilisant cette classe continuent à
fonctionner
• Si une interface n’est plus suffisante – Ne pas ajouter des méthodes abstraites– Sinon, les classe qui sont conformes à l’interface ne
le seront plus (très coûteux à modifier toutes ces classes!)
– On définit plutôt une sous-interface– interface SousInterface extends SuperInterface
Extension multiple d’interface
• Une interface peut extends plusieurs autres interfaces
DataInput
«interface»
DataOutput
«interface»
DataIO
«interface»
interface DataIO extends DataInput, DataOutput { }
instanceOf
• Tester si une instance est d’une classe (sous-classe)• Fonctionne aussi pour tester si une instance est du type
d’une interface (se conforme à une interface)• Exemple:
interface DataIO extends DataInput, DataOutput { }DataIO refInterface;BankAccount compte;
…
if (refInterface instanceOf DataOutput) …
if (compte instanceOf Movable) …
Utilisation d’interface et de classe
• Interface comme type de donnée – Partagent les méthodes
• Classe comme type de données – Partagent les méthodes et attributs
• Les deux peuvent se convertir– refInterface instance – refClasse instance– Casting:
• (Interface).refClasse: utile?– refClasse peut faire la même chose que (Interface).refClasse.
• (Classe).refInterface: utile!– Accéder à d’autres attributs et méthodes de la Classe
Exemple d’interface en Java
• Collection
Collectionpublic interface Collection<E> extends Iterable<E> { //Basic operations int size(); boolean isEmpty(); boolean contains(Object element); boolean add(E element); //optional boolean remove(Object element); //optional Iterator iterator(); //Bulk operations boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); //optional boolean removeAll(Collection<?> c); //optional boolean retainAll(Collection<?> c); //optional void clear(); //optional //Array operations Object[] toArray(); <T> T[] toArray(T[] a);}
<E>: Genetic
Traverser une collection (aperçu)
public interface Iterator<E> { boolean hasNext(); E next(); void remove(); //optional}
Utilisation:Supposons: boolean cond(Object)
static void filter(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (!cond(i.next())) i.remove();}
Listpublic interface List<E> extends Collection<E> { //Positional access E get(int index); E set(int index, E element); //optional boolean add(E element); //optional void add(int index, E element); //optional E remove(int index); //optional abstract boolean addAll(int index, Collection<? extends E> c); //optional
//Search int indexOf(Object o); int lastIndexOf(Object o);
//Iteration ListIterator<E> listIterator(); ListIterator<E> listIterator(int index);
//Range-view List<E> subList(int from, int to);}
ArrayList
java.util Class ArrayList<E>
java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java.util.ArrayList<E>
All Implemented Interfaces:
Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess
Hiérarchie des classes
Comparaison avec AbstractListpublic abstract class AbstractList<E>extends AbstractCollection<E>implements List<E>
{
// Méthodes implantées:
void add(int index, E element) {…}
void clear() {…}
int hashCode() …
}
Inner class: concept• Définir une classe qui a une utilité locale comme inner classs:• public class DataSetTester3
{ public static void main(String[] args) {
class RectangleMeasurer implements Measurer { . . . }
Measurer m = new RectangleMeasurer(); DataSet data = new DataSet(m);. . . }
} • Dans une inner class, on peut accéder aux méthodes et attributs de la
classe qui l’englobe (DataSetTesters)