420 likes | 850 Views
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
E N D
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 max public 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 comptes meilleirClient = 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: • La méthode ne peut pas être implantée pour la classe mère, mais elle le peut pour les sous-classes • 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 Non implantable 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
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 Ordre Object BankAccountMot 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
Classe abstraite • Déclaration abstract public class Nom { … } • Exemple abstract 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 extendsClasse • 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
Exemple abstract class Forme { int x, y; // coordonnée repère de la forme abstract 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 formes abstract 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 tousref1 et ref2de 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: publicclassDataSetTester • 05: { • 06: publicstaticvoidmain(String[]args) • 07: { • 08: DataSetbankData=newDataSet(); • 09: • 10: bankData.add(newBankAccount(0)); • 11: bankData.add(newBankAccount(10000)); • 12: bankData.add(newBankAccount(2000)); • 13: • 14: System.out.println("Average balance = " • 15: +bankData.getAverage()); • 16: Measurablemax=bankData.getMaximum(); • 17: System.out.println("Highest balance = " • 18: +max.getMeasure()); • 19: • 20: DataSetcoinData=newDataSet(); • 21: • 22: coinData.add(newCoin(0.25,"quarter")); • 23: coinData.add(newCoin(0.1,"dime")); • 24: coinData.add(newCoin(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 à DataSetDataSet 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
Interface Weapon «interface» wields Explorer Weapon Sword Pen MissileLauncher
“Héritage” Multiple d’interfaces par une classe class Sword implements Weapon, Movable {…}
Extension d’interface • Assume all weapons are movable: 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 • interfaceDataIOextendsDataInput, 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
Collection public 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(); }
List public 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 AbstractList public 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)