Encapsulation - Classes internes

publicité
Encapsulation
L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles
pour les autres objets.
La visibilité dépend des membres : certains membres peuvent être visibles et
d'autres non.
La visibilité dépend de l'observateur : les membres de l'objet encapsulé peuvent
être visibles pour certains objets mais pas pour d'autres.
L'encapsulation a pour objectif d'améliorer la robustesse et l'évolutivité des
programmes.
1
Robustesse du code et encapsulation
Les objets doivent pouvoir protéger les données qu'ils contiennent.
class Date{
// attributs
int jour;
int mois;
int annee;
...
}
class BilleterieSNCF{
// attributs
Date d;
...
}
class ProgrammeFarceur{
...
void faitFarce(BilleterieSNCF b){
b.d.jour = 32;
}
}
Les objets doivent pouvoir protéger les méthodes qu'ils contiennent.
class Tetris{
...
Piece creerNouvellePiece(){
...
}
}
class ProgrammeEtourdi{
...
void faitErreur(Tetris t){
Tetris t = ...
t.creerNouvellePiece();
t.creerNouvellePiece();
}
}
2
Evolution du code et encapsulation
class PileDeChaines{
// attributs
String[] pile;
// méthodes
void push(String s){
// ajouter s à la fin de pile
}
String top(){
// renvoyer le dernier élément de pile
}
String pop(){
// enlever le dernier élément de pile et le renvoyer
}
boolean estVide(){
// renvoyer vrai si la taille de pile est 0, faux sinon
}
}
class PileDeChaines{
// attributs
ArrayList<String> pile;
// méthodes
...
}
3
Que faut-il montrer?
Principe de David Parnas :
Une classe doit rendre visible ce qui est nécessaire pour
manipuler ses instances et rien d'autre.
L'implémentation d'une méthode doit utiliser ce qui est
nécessaire au traitement qu'elle réalise et rien d'autre.
4
Encapsulation des données
Par défaut, les attributs doivent être cachés. Leurs valeurs ne doivent être
visibles et modifiables qu'au travers des méthodes. Il est cependant
acceptable de laisser visible les constantes.
objet o1
méthodes
(accesseurs)
objet o2
m1
attributs
objet o3
m2
5
Encapsulation des méthodes
Les méthodes intermédiaires qui ne sont pas destinées à être utilisées à
l'extérieur de la classe doivent être cachées.
class ListeDeTruc{
...
// méthodes
void coupe(Truc pivot){
...
}
void trier(){
...
this.coupe(...);
...
}
...
}
6
Paquetages Java (1/4)
En Java, il existe deux périmètres de visibilité : les classes et les paquetages.
Un paquetage est un regroupement de classes. Les paquetages sont organisés
hiérarchiquement comme des répertoires de classes.
java
java.lang
java.io
java.lang.annotation
Annotation
java.nio
java.math
java.lang.instrument
java.net
java.lang.reflect
AnnotationTypeMismatchException
java.text
java.util
java.sql
...
...
...
Les noms des paquetages suivent la convention inverse des URI internet :
com.monlogiciel.paquetage2
7
Paquetages Java (2/4)
Pour utiliser dans un fichier java une classe C d'un paquetage p, on peut :
- donner le nom de la classe in extenso :
- ajouter une directive en tête du fichier :
class Truc{
...
p.C variable = ...
...
}
import p.C;
import java.lang.*;
class Truc{
...
C variable = ...
...
}
import static java.lang.Math.PI;
On peut éviter de préfixer les constantes de
classes par le nom de leur classe en utilisant
import static :
class Truc{
...
float f = PI*3;
...
}
8
Paquetages Java (3/4)
Pour organiser ses propres classes en paquetage :
- placer les classes dans un répertoire portant le nom souhaité
- mettre en tête de fichier la directive package correspondante
répertoire monpaquetage
package monpaquetage;
package monpaquetage;
package monpaquetage;
class Truc{
...
}
class Machin{
...
}
...
La compilation et l'exécution de ces classes doit se faire en précisant le
chemin qui y mène : javac -classpath …/monpaquetage/Truc.java
9
Paquetages Java (4/4)
Les paquetages représentent des espaces de nommage : deux paquetages
peuvent contenir des classes de même nom.
Exemple : les 3 interfaces javax.lang.model.element.Name, javax.naming.Name et
javax.xml.soap.Name sont différentes.
Les paquetages permettent d'organisation les classes par thèmes, par
applications.
Exemples : java.applet contient les classes dédiées à la réalisation d'applications
clientes pour pages web, java.security regroupe les classes dédiées à la gestion de la
sécurité.
Les paquetages permettent de moduler l'encapsulation.
10
Niveaux d'encapsulation (1/2)
Les 4 niveaux d'encapsulation de Java sont par ordre de visibilité croissante :
– un membre privé (private) n'est visible que dans les instances
directes de la classe où il est déclaré.
– un membre sans modifieur est visible uniquement dans les instances
directes de la classe où il est déclaré et dans celles des classes du
même paquetage.
– un membre protégé (protected) n'est visible que dans les instances,
directes ou non, de la classe où il est déclaré (et donc aussi dans les
instances des sous-classes) et dans les instances des classes du
même paquetage.
– un membre public (public) est visible par n'importe quel objet.
Ces 3 modifieurs se retrouvent en C++, Python, etc.
11
Niveaux d'encapsulation (2/2)
Visibilité des membres selon leurs modifieurs et le niveau d'encapsulation
modifieur
classe
private
visible
paquetage
sousclasses
visible
visible
protected
visible
visible
visible
public
visible
visible
visible
autres
classes
visible
12
Encapsulation des attributs
Les attributs doivent a priori être privés (ou au moins protégés). Si besoin, des
accesseurs et modifieurs publics sont définis et permettent de contrôler
l'accès aux attributs.
class Personne{
// attributs
private String nom;
private Vote v;
private int pointure;
private float fortune;
...
// methodes
public String getNom(){
return this.nom;
}
public int getPointure(){
return this.pointure;
}
public void donnerSous(float s){
this.fortune = this.fortune.s;
}
public float getFortune(Object o){
if(o instanceof Etat) return this.fortune;
}
}
13
Encapsulation et héritage
La redéfinition d'une méthode doit avoir une visibilité au moins égale à celle
de la méthode de la super-classe. Cette contrainte est due à la liaison
dynamique.
class Truc{
...
public void m(){
...
}
}
class Machin extends Truc{
...
private void m(){
...
}
}
Truc t = new Machin();
t.m(); ??
Le masquage d'un attribut, géré par liaison statique, ne pose aucune
contrainte sur l'encapsulation.
14
Encapsulation et abstraction
Une méthode abstraite ne peut être privée car elle doit être implémentée dans
une sous-classe. Elle peut être implémentée par une méthode ayant une
visibilité plus large qu'elle-même.
abstract class Truc{
...
abstract void m1();
protected abstract void m2();
...
}
class Machin extends Truc{
...
protected void m1(){
...
}
protected void m2(){
...
}
}
Une interface ne contient que des membres publics ou sans modifieur de
visibilité.
Les membres de classe se comportent comme les membres d'instances du
point de vue de l'encapsulation.
15
Encapsulation des classes
Une classe (ou interface) déclarée public est visible de partout, sinon elle
n'est visible que dans son paquetage.
package monPaquetage;
public abstract class Liste{
public void ajoutElement(Object o);
public Object enleverElement(Object o);
public boolean estVide();
public Liste creerListe(){
return new ImplementationDeListe();
}
...
}
package monPaquetage;
class ImplémentationDeListe extends Liste{
...
}
Les classes qui ne sont pas déclarées dans un paquetage font toutes partie du
même paquetage « anonyme ».
16
Classes internes
Une classe interne est une classe définie à l'intérieur d'une autre classe.
Une classe membre est définie au même niveau que
les attributs et méthodes de la classe englobante.
class A{
...
class B{
...
}
}
Une classe locale est définie à l'intérieur d'une
méthode.
public void method(){
class B{
...
}
...
}
Une classe anonyme est définie à l'intérieur d'une
expression.
Objet o = new B(){
...
}
17
Classe membre
Toute instance d'une classe membre est associée à une instance de la
classe englobante.
Une classe membre n'a donc de sens que si ses instances ne peuvent
exister que comme parties d'instances de la classe englobante.
class MorceauDeGruyere{
...
class TrouDeGruyere{
...
}
...
}
class Voiture{
...
class RoueDeVoiture{
...
}
...
}
On peut imbriquer des classes sur autant de
niveaux que l'on veut.
class Feu{
...
class Fumee{
...
class SignauxDeFumee{
...
}
}
}
18
Classe membre et encapsulation
Une classe membre a accès aux attributs et méthodes de la classe
englobante, même s'ils sont privés.
Une classe englobante à accès à tous les membres de sa classe interne
même ceux qui sont privés.
class A{
private int z;
L'accès à l'instance de la classe
englobante se fait dans la classe membre
par NomClasseEnglobante.this (s'il
n'y a pas d'ambiguité, le nom du membre
de la classe englobante suffit).
public void methode(){...}
...
class B{
...
A.this.methode();
z = 12;
...
}
}
19
Instanciation d'une classe membre
L’instanciation de la classe membre se fait à travers une instance de la classe
englobante.
class A{
class B{
class C{
...
}
...
}
...
public static void main(String[] t){
A instanceDeA = new A();
B instanceDeB = instanceDeA.new B();
A.B autreB = new B();
A.B.C unC = instanceDeB.new C();
}
}
20
Classe membre et héritage
L'héritage est totalement indépendant de l'imbrication de classe.
class MorceauDeGruyere extends Aliment{
...
class TrouDeGruyere extends EspaceCirculaire implements Vide{
...
}
...
}
interface Vide{
public void remplir(Matiere m);
}
class EspaceCirculaire{
private int rayon;
...
}
class Humain{
...
class Foetus extends Humain{
...
}
...
}
21
Classe membre et abstraction
Une interface ou une classe abstraite peuvent être membres d'une classe.
class File {
interface FileParser {
boolean parse();
}
class CSVParser implements FileParser {
public void parse() {...}
}
class ODSParser implements FileParser {
public void parse() {...}
}
private FileParser fp;
public File(String name){
...
if(isCSV(name)) this.fp = new CSVParser();
if(isODS(name)) this.fp = new ODSParser();
...
}
}
22
Classe membre de classe
Si la classe membre est déclarée statique, elle n'est pas liée à une instance
de la classe englobante.
Le mot clé this ne peut y être employé, donc la classe membre de classe n'a
pas accès aux attributs et méthodes non statiques de la classe englobante.
Une classe statique a accès à tous les membres statiques de la classe
englobante.
class A{
static class B{
...
}
Il est possible d'instancier une
classe membre statique sans
passer par une instance de la
classe englobante.
...
public static void main(String[] t){
B instanceDeB = new B();
}
}
23
Classe membre et JVM
Le compilateur insère automatiquement dans la classe membre un attribut
privé qui référence l'instance englobante.
Le compilateur ajoute automatiquement à tous les constructeurs de la classe
membre un argument caché qui pointe sur la classe englobante. Il ajoute
aussi des accesseurs vers les membres privés dans les deux classes.
La JVM gère les classes membres comme des classes normales.
A.class
class A{
class B{
...
}
...
compilation
A$B.class
}
24
Classe locale (1/3)
class A{
public void method(){
class B{
...
}
...
}
Une classe locale n'est visible que dans le
bloc de code où elle est définie (elle est
forcément « privée »).
}
Une classe locale définie dans une méthode d'instance a accès aux attributs et
méthodes de la classe englobante, même s'ils sont privés.
Une méthode locale définie dans une méthode de classe n'a accès qu'aux
membres de classes de la classe englobante.
25
Classe locale (2/3)
Une classe locale ne peut utiliser une
variable locale que si elle est déclarée
final.
Une class locale ne peut être définie que
statique ou abstraite.
Le compilateur crée pour
chaque classe locale un
fichier .class numéroté.
class A{
...
void methode(){
class B{
...
}
...
class C{
...
}
}
...
}
class A{
public void method(){
final int i = ...
int j = ...
class B{
int k = i;
int l = j;
...
}
...
}
}
A$1$B.class
compilation
A$2$C.class
26
Classe locale (3/3)
Une classe locale ne sert pas vraiment à modéliser des données, mais
constitue une technique permettant de définir localement un type.
Le plus souvent, on utilise une classe locale pour spécialiser une classe
existante et réutiliser ainsi du code localement.
class Outil{
...
}
class BuveurDeVin{
public void deboucherBouteille(Bouteille b){
class TireBouchon extends Outil{
...
}
TireBouchon tb = new TireBouchon();
tb.debouche(b);
...
}
}
27
Classe anonyme (1/2)
Une classe anonyme est une classe locale sans nom, définie dans une
instruction et instanciée dans la foulée.
interface ActionListener{
public void actionPerformed(ActionEvent ae);
}
class InterfaceGraphique{
public InterfaceGraphique(){
...
Button bouton ...
bouton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
...
}
};
...
}
...
}
Une classe anonyme ne peut être réutilisée, ne peut avoir qu'une seule
instance et n'a pas de constructeur (l'instance unique est créée avec le
constructeur par défaut).
28
Classe anonyme (2/2)
Une classe anonyme n'autorise aucun modifieur et est toujours final
(implicitement).
Une classe anonyme subit les mêmes restrictions d'accès aux membres de la
classe englobante qu'une classe locale.
Le compilateur génère
pour
chaque
classe
anonyme
un
fichier
.class numéroté.
class A{
...
void methode(){
new class B(){
...
}
...
}
...
}
compilation
A$1.class
29
Téléchargement