Architecture INTERFACE et Design Pattern JAVAbliaudet.free.fr/IMG/pdf/Archi-5-1-Interface.pdf ·...
Transcript of Architecture INTERFACE et Design Pattern JAVAbliaudet.free.fr/IMG/pdf/Archi-5-1-Interface.pdf ·...
JAVA – Interface - page 1/21 - Bertrand LIAUDET
Architecture
INTERFACE et Design Pattern JAVA
SOMMAIRE
SOMMAIRE 1
INTERFACE 2Interface – présentation générale 2
Présentation 2Syntaxe 5Interface et polymorphisme – Principe de substitution 8Distinction avec les classes abstraites 10
Interface – 3 exemples d’usages possibles 111 - Découplage entre classe client et classe modèle : interface proposée et interface utilisée 112 - Interface et héritage multiple de spécifications (ou d’usages) 143 - Avoir des méthodes « variables » 16
Exercices 21Tester les codes 21Compléter les codes 21
Version avril 2019
JAVA – Interface - page 2/21 - Bertrand LIAUDET
INTERFACE
Interface – présentation générale
Présentation
Polysémie
Le terme interface a couramment plusieurs sens distincts : • Dans un sens général, c’est la partie située entre deux éléments matériels ou logiciels qui
permet l’échange d’informations. Par exemple, l’IHM (interface homme-machine), c’est l’écran, le clavier, la souris, etc. L’IHM permet l’échange d’informations entre l’homme et la machine (le logiciel).
• Au sens de la POO, d’un point de vue fonctionnel, l’interface d’une classe est la partie publique (public ou de niveau paquetage) de la classe, que ce soit ses méthodes ou ses attributs. En général, il s’agit donc d’une liste de méthodes permettant d’utiliser la classe et de la considérer comme une « boite noire ».
• Au sens de la POO, d’un point de vue technique, une interface c’est aussi un ensemble de méthodes abstraites (donc d’en-têtes de méthodes) qui seront à réaliser (à coder) par les classes qui implémenteront l’interface. C’est aussi un ensemble de constantes. Cela conduit à l’utilisation d’un nouveau mot-clé : « interface ».
• En programmation, la notion d’API, Application Programming Interface, designe un ensemble de bibliothèques, de fonctions, de classes et/ou d’objets utilisables dans le code. Les bibliothèques Java sont des API (avec toutes leurs classes). Le DOM JavaScript est une API (avec son objet « document »).
• En programmation WEB, la notion d’API web désigne un ensemble de services ou de fichiers qu’un site WEB met à disposition pour le développement d’un autre site WEB.
Toutes ces significations se rejoignent. Il faut essayer d’en comprendre le principe.
JAVA – Interface - page 3/21 - Bertrand LIAUDET
Présentation technique de P.O.O.
• Une interface est une classe abstraite qui n’a pas d’attributs autres que des constantes de classe et qui n’a que des méthodes abstraites : c’est donc un cas particulier de classe abstraite.
• Une interface ne peut pas être instanciée, mais on peut déclarer des objets de type interface. • La relation entre une classe et une interface n’est plus une relation d’héritage mais une
relation d’implémentation : une classe implémente (ou implante ou réalise) une interface. Une classe qui implémente une interface doit coder les méthodes de l’interface. Toutefois, une classe abstraite peut implémenter une interface avec des méthodes abstraites qui seront donc finalement implémentées par les méthodes des classes réalisant la classe abstraite.
• Il faut distinguer entre implémenter une méthode (forcément abstraite) et redéfinir une méthode (override) forcément concrète, et surcharger une méthode (overload) forcément concrète aussi.
• Une classe peut implémenter plusieurs interfaces tandis qu’elle ne peut hériter que d’une seule classe de base, qu’elle soit abstraite ou pas.
• Une interface peut hériter d’une autre interface. • Une interface est soit « public », soit du niveau de son paquetage. • Les constantes sont forcément « public static final » et rien d’autre. • Les méthodes sont forcément « public abstract » et rien d’autre.
JAVA – Interface - page 4/21 - Bertrand LIAUDET
Présentation fonctionnelle : interface proposée et interface utilisée
Ø Fonctionnalités proposées
Une interface peut être vue comme étant un ensemble de fonctionnalités proposées par une classe, fonctionnalités qui pourront être ensuite utilisées par une autre classe. En tant que fonctionnalités proposées, l’interface est un contrat qui impose aux classes qui l’implémentent de coder les en-têtes que l’interface définit.
Ø Fonctionnalités à utiliser
En tant que fonctionnalités à utiliser, une interface définit un protocole d’utilisation (comme n’importe quelle classe qu’on utilise) pour les classes qui vont l’utiliser. Une classe qui utilise une interface instanciera un objet d’une classe qui réalise cette interface.
Ø Formalisme UML :
La flèche de réalisation d’interface est la même que celle de l’héritage mais le trait est en pointillé. La flèche de dépendance (trait en pointillé, pointe en V) est une flèche qui dit que la classe source (« ClasseQuiUtilise ») utilise un objet de la classe cible (IClasseQuiPropose).
<<réalise>><<use>>ClasseQuiUtilise ClasseQuiRealiseIClasseQuiPropose
JAVA – Interface - page 5/21 - Bertrand LIAUDET
Syntaxe
Déclaration
public interface I { int MAX = 1000; void methode1(); int methode2 (String ch, MaClasse maClasse); }
Une interface se déclare comme une classe mais : • Une interface peut être « public » ou de niveau paquetage (pas de modificateur). • On utilise le mot-clé « interface » à la place de « class » pour définir une interface. • Les méthodes d’une interface sont des méthodes abstraites : elles n’ont pas de corps mais
que leurs signatures (donc pas de bloc ouvert et fermé par des accolades). • Les méthodes d’une interface sont forcément « public abstract » : ces modificateurs sont
donc facultatifs. • Les constantes sont forcément « public static final » : ces modificateurs sont donc
facultatifs.
Ø Commentaires
Etant donné qu’une interface est un contrat de réalisation de méthodes dont la signature est fixée et dont l’usage peut être associé à des constantes elles-mêmes fournies par l’interface, il est prudent de préciser clairement en commentaire ce qu’on attend des méthodes à réaliser, et de préciser clairement la signification des constantes.
JAVA – Interface - page 6/21 - Bertrand LIAUDET
Implémentation - Réalisation
Ø Une classe implémente (ou réalise) une interface class A implement I { … void methode1(){ // implementation de methode1 ; // utilisation possible de MAX directement } int methode2 (String ch, MaClasse maClasse, etc…){ // implementation de methode2 // utilisation possible de MAX directement } … }
On peut utiliser MAX directement (sans le préfixer par le nom de l’interface). Comme toute constante de classe, MAX est aussi utilisable par une classe qui n’implémente pas l’interface en préfixant son nom par celui de l’interface : « I.MAX ».
JAVA – Interface - page 7/21 - Bertrand LIAUDET
Subtilités
Ø Dérivation d’interface
Une interface peut dériver (hériter) d’une ou plusieurs autres interfaces : ce qui veut dire que pour la réaliser, il faudra aussi réaliser toutes les méthodes des interfaces dont elle dérive. public interface I extends I1, I2, I3 { … ]
Déclarer I dérivant de I1, I2 et I3 c’est exactement la même chose que de déclarer I en y ajoutant toutes les méthodes et tous les attributs de I1, I2 et I3.
Ø Une classe peut implémenter plusieurs interfaces class A implement I1, I2, I3 { … }
A noter que dans le cas d’une implémentation multiple, si les interfaces proposent plusieurs fois la méme méthode avec la même signature, alors il suffira de réaliser la méthode une fois. Deux interfaces proposant deux méthodes avec les mêmes paramètres mais un type de retour différent seront nécessairement incompatibles car les deux méthodes ne pourront pas être implémentées en même temps.
Ø Une classe peut dériver d’une autre classe et implémenter plusieurs interfaces class A extends B implement I1, I2, I3 { … }
Ø Objet interface et méthode
Une méthode peut retourner une interface et peut aussi avoir une interface en paramètre. C’est la même chose avec une classe abstraite. Bien sûr, les objets effectivement passés en paramètre à la méthode ou renvoyés par la méthode seront des objets de classe réalisant l’interface ou la classe abstraite.
JAVA – Interface - page 8/21 - Bertrand LIAUDET
Interface et polymorphisme – Principe de substitution
Objet « interface » et polymorphisme : règle de substitution
On peut déclarer un objet de type Interface. Bien sûr, on ne peut pas instancier un objet de type Interface. Par contre, puisque tout objet d’une classe de base est substituable par un objet d’une de ses classes dérivées (principe de substitution), on peut affecter à un objet interface une instance d’une classe qui réalise l’interface. IC i ; i = new C();
Avec un objet de l’interface IC, on pourra manipuler tous les objets des classes qui implémentent IC.
JAVA – Interface - page 9/21 - Bertrand LIAUDET
Code correspondant au formalisme UML :
<<réalise>><<use>>Main Classe
+ <<Implement>> m1 ()
IClasse
+ m1 ()
public interface IClasse { void m1(); }
public class Classe implement IClasse { ... }
public class Main { ... IClasse obj ; obj = new Classe(...) ; obj.m1() ; ... }
JAVA – Interface - page 10/21 - Bertrand LIAUDET
Distinction avec les classes abstraites
L’interface est un cas particulier de classe abstraite
Une interface est un cas particulier de classe abstraite (classe abstraite qui n’a pas d’attributs autres que des constantes et qui n’a que des méthodes abstraites). Les interfaces ont le même fonctionnement polymorphe que les classes abstraites.
Ø Exemple :
On peut reprendre l’exemple donnée pour les classes abstraites, exemple pour lequel la classe abstraite n’a pas de méthodes réalisées et pas d’attribut, et on peut remplacer la classe abstraite par une interface et obtenir le même fonctionnement polymorphe.
Distinction entre interface et classe abstraite
Dans le cas d’un héritage, on s’intéresse à la relation « est-un » qui est une relation « ontologique » c’est-à-dire qu’elle concerne surtout les attributs communs. Dans le cas d’une interface, on s’intéresse à la relation « sait faire » qui est une relation « fonctionnelle ». Il ne s’agit plus de dériver d’un autre objet mais de savoir faire un certain nombre de choses. On s’intéresse surtout aux méthodes.
JAVA – Interface - page 11/21 - Bertrand LIAUDET
Interface – 3 exemples d’usages possibles
1 - Découplage entre classe client et classe modèle : interface proposée et interface utilisée
Principe
La notion d’interface permet d’accentuer encore un peu plus l’encapsulation en définissant les méthodes utiles à l’utilisation d’une classe ou d’un paquetage dans une classe interface. Ainsi l’utilisateur pourra directement déclarer un objet de type interface, puis instancier un objet réalisant l’interface.
Modèle UML général
<<réalise>><<use>>ClasseQuiUtilise ClasseQuiRealiseIClasseQuiPropose
ou
<<réalise>>ClasseQuiUtilise ClasseQuiRealiseIClasseQuiPropose
La composition signifie que la ClasseQuiUtilise contient un attribut de classe IClasseQuiPropose.
JAVA – Interface - page 12/21 - Bertrand LIAUDET
Exemple de découplage de l’interface utilisateur
<<réalise>>Ecran Calcul
ICalcul
++
m1 ()m2 ()
public Ecran(){ ICalcul calcul; Ecran(ICalcul calcul){ this.calcul = calcul;} ... void test(){ ... calcul.m1() ; ... } }
Ø Remarques
• calcul est un attribut de la classe Ecran • Le découplage fait que la méthode test() fonctionne pour tout objet réalisant ICalcul. Avec
le constructeur, seule l’instantiation d’un Ecran est dépendante du Calcul : Ecran e=new Ecran(new Calcul()) ;
JAVA – Interface - page 13/21 - Bertrand LIAUDET
Exemple : le design pattern Adapter
Le pattern adapter permet d’ajouter une nouvelle classe ou un nouveau composant à un modèle en faisant en sorte que l’interface du modèle ne change pas et donc que le client puisse continuer à fonctionner identiquement. L’adaptateur se branche sur l’interface du modèle en intégrant la nouvelle classe ou le nouveau composant. Le pattern Adapter est utile quand on veut intégrer un composant existant déjà et dont l’interface n’est pas standard par rapport au client de notre modèle.
Modèle de départ
NouvelleClasse est une classe à adapter au
modèle et à sont interface
Classe ajoutée pour permettre l 'adaptation au
modèle de l 'élément à adapter
<<realize>>
<<realize>>
nouvelleClasseAdaptee
<<use>>
Adapter
- nouvelleClasseAdaptee : NouvelleClasse = new NouvelleClasse()+ <<Implement>> operation (int nombre1, int nombre2) : void
InterfaceStandard
+ operation (int pNombre1, int pNombre2) : void
ClasseDuModele
+ <<Implement>> operation (int nombre1, int nombre2) : void
MainClient
+ main (String args[]) : void
NouvelleClasse
++
operation1 (int nombre1, int nombre2)operation2 (int nombre)
: int: void
JAVA – Interface - page 14/21 - Bertrand LIAUDET
2 - Interface et héritage multiple de spécifications (ou d’usages)
Le problème de l’héritage multiple
L’héritage multiple n’est pas pris en compte en Java. La difficulté de l’héritage multiple vient du fait que les méthodes peuvent apparaître à plusieurs niveaux du réseau d’héritage qui n’est plus une simple branche d’arbre. En cas d’ajout d’un héritage multiple sur un système fonctionnant déjà, on risque donc d’utiliser une méthode à la place d’une autre tandis qu’on ne le souhaitait pas.
La solution de l’interface
Une interface permet de gérer de l’héritage multiple en le limitant au niveau de la signature des méthodes (l’en-tête) et non pas du corps des méthodes. Cela supprime tous les risques de conflit au niveau des méthodes puisqu’une méthode ne pourra finalement être réalisée qu’une seule fois. D’un point de vue méthodologique, dans un héritage multiple, il faut définir l’héritage principal (ou la filiation) à partir des attributs puis considérer tous les autres comme des interfaces, c’est-à-dire comme des héritages qui se limiteront à des méthodes abstraites. D’un point de vue pratique, l’héritage multiple via des interfaces oblige tout de même à implémenter le code des méthodes. La généralisation se limite à l’en-tête. Son intérêt est donc surtout de normaliser l’interface pour les utilisateurs.
JAVA – Interface - page 15/21 - Bertrand LIAUDET
Exemple
<<réalise>><<réalise>>
<<réalise>>
Etudiant
ISalarié
++
UsageSalarié 1 ()UsageSalarié 2 ()
Personne{abstract}
---
nomadressetél
: String: String: String
+ afficherCoordonnées ()
Salarié
IEtudiant
++
UsageEtudiant 1 ()UsageEtudiant 2 ()
Dans ce cas, Etudiant et Salarié héritent de Personne : ils ont un nom, une adresse et un tél qu’on peut afficher. Par ailleurs le Salarié réalise les usages imposés dans ISalarié et l’Etudiant ceux imposés par IEtudiant. On considère que l’étudiant « est un » salarié. L’Etudiant ne peut pas hériter du Salarié puisqu’il hérite déjà de la classe personne. Par contre, il va réaliser l’interface ISalarié, héritant ainsi en quelque sorte des Usages du salarié. Les spécifications sont imposées par l’interface mais il faudra tout de même recoder les méthodes déjà codées dans Salarié.
JAVA – Interface - page 16/21 - Bertrand LIAUDET
3 - Avoir des méthodes « variables »
Héritage vs. Délégation
La délégation offre un mécanisme de réutilisation aussi puissant que celui offert par la généralisation. L’héritage est une construction rigide mais la propagation des attributs et des méthodes est automatique. L’héritage correspond à une relation « est-un » stricte, c’est-à-dire pas à une relation « a-un-comportement-de ». La délégation est une construction plus souple basée sur l’agrégation. La propagation des propriétés doit être réalisée manuellement. Elle permet généralement la mise en œuvre de généralisation multiple.
JAVA – Interface - page 17/21 - Bertrand LIAUDET
Ø Héritage
dormir :chanterBerceuse();
dormir :if getAge() <10 raconterHistoire();
Personne[] tab=new Personne[4];
tab[0]=new Bebe("Lawrence", 1);tab[1]=new Enfant("Berenice",9);tab[2]=new Enfant("Aurelien",5);
tab[3]=new Personne("Bertrand",49);
for(int i=0; i<tab.length; i++) tab[i].dormir();
<<use>>
Bebe
+++
<<Constructor>><<Override>>
Bebe (String nom, int age)dormir ()chanterBerceuse ()
: void: void
Personne
--
nomage
: String: int
++++
<<Constructor>> Personne (String nom, int age)getNom ()getAge ()dormir ()
: String: int: void
Enfant
+++
<<Constructor>><<Override>>
Enfant (String nom, int age)dormir ()raconterHistoire ()
: void: void
Main
+ main (String args[]) : void
Ici le mécanisme est un mécanisme classique d’héritage et de polymorphisme.
JAVA – Interface - page 18/21 - Bertrand LIAUDET
Ø Délégation – polymorphisme par délégation
Personne[] tab=new Personne[4];
tab[0]=new Personne("Lawrence", 1, new Bebe());tab[1]=new Personne("Berenice",9, new Enfant());tab[2]=new Personne("Aurelien",5, new Enfant());
tab[3]=new Personne("Bertrand",49,new Sommeil());
for(int i=0; i<tab.length; i++) tab[i].dormir();
<<use>>
dormir (p) :chanterBerceuse();
dormir (p) :if p.getAge() <10 raconterHistoire();
dormir :s.dormir(this);
s
Bebe
++
<<Override>> dormir (Personne p)chanterBerceuse ()
: void: void
Sommeil
+ dormir (Personne p) : void
Enfant
++
<<Override>> dormir (Personne p)raconterHistoire ()
: void: void
Main
+ main (String args[]) : void
Personne
---
nomages
: String: int: Sommeil
++++
<<Constructor>> Personne (String nom, int age, Sommeil s)getNom ()getAge ()dormir ()
: String: int: void
Ici on obtient le polymorphisme par la délégation. On fournit l’objet « p » à la méthode dormir pour accéder aux méthodes de Personne, si nécessaire (ici : if p.getAge <10…). On peut considérer qu’on « sette » une méthode spécifique à la personne au moment de son instanciation : « new Personne("Lawrence", 1, new Bebe()); » consiste à setter la méthode « dormir » des Bébé à la personne, comme on lui a setté son prénom et son âge. Cette technique sera particulièrement utile en cas d’héritage multiple car cette fois-ci elle offrira une solution plus performante que la solution de l’héritage classique. On verra ça particulièrement dans le design pattern Stratégie.
JAVA – Interface - page 19/21 - Bertrand LIAUDET
Exemple : le pattern Strategy (délégation)
http://rpouiller.developpez.com/tutoriel/java/design-patterns-gang-of-four/?page=page_4#LVI-I
Ø Description du pattern (objectif, définition)
• Encapsule des comportements d’une même famille (des méthodes) et utilise la délégation pour savoir lequel utiliser.
• « sette » des méthodes à travers une interface : permet ainsi d’avoir une méthode « variable ».
• Adapter le comportement d’un objet en fonction d’un besoin sans changer les interactions, et donc indépendamment du client.
• Définir une famille d'algorithmes interchangeables et permettre de les changer indépendamment de la partie cliente.
Ø Principes de résolution
Quand un objet Entité est instancié par un objet Client, il est instancié avec une stratégie concrète (un objet de Strategie1 ou un objet de Strategie2). De ce fait, la méthode calcul de l’objet Entité (qui exécute strategie.calcul() ) réagit différement selon la stratégie concrète instancié. Ainsi, les objets de la classe Entité accèdent de façon polymorphe aux méthodes de la classe « Stratégie » La classe Stratégie est une interface qui définit les comportements. Les stratégies concrètes réalisent cette interface.
JAVA – Interface - page 20/21 - Bertrand LIAUDET
UML
1# strategieEntité
+ calcul ()
Strategie 1
+ <<Implement>> calcul ()
Strategie
+ calcul ()
Client
+ main (String args[]) : void
Strategie 2
+ <<Implement>> calcul ()
JAVA – Interface - page 21/21 - Bertrand LIAUDET
Exercices
Tester les codes
Chargez les codes « Archi-5-1-Interface-code-POO.zip » Pour tester l’exemple et faire les exercices, il faut un JDK : les commandes javac et java doivent être reconnues dans une console. L’objectif est surtout de tester les exemples 50, 51 et 52. Chaque dossier contient un lisez-moi. Une fois les exemples installés et testés, il faut regarder le code pour le comprendre.
Compléter les codes
Exemples 50
Ajoutez le cas d’un adolescent : l’âge sera compris entre 16 et 20 ans. La méthode de sommeil sera : consulter les réseaux sociaux.
Exemples 51
Ajouter un moteur télécommandé au système et créer un 2ème leurre dans le main, d’abord « normal », puis en lui donnant un moteur télécommandé.