next up previous contents index
suivant: 3.5 Surcharge monter: 3. Classes d'objets précédent: 3.3 Membres statiques   Table des matières   Index


3.4 Patterns d'accès et discipline d'encapsulation

L'encapsulation est une technique de programmation qui permet de cacher les détails d'implémentation d'un objet pour ses utilisateurs, ou l'état interne d'un système. Java donne plusieurs moyens pour assurer cette encapsulation, et il appartient au programmeur de les utiliser à bon escient. Afin d'empêcher l'utilisateur d'accéder directement aux champs de l'objet, on peut déclarer ses champs private et offrir éventuellement des méthodes de lecture ou d'écriture de ces champs, formés selon l'usage par get ou set (en français, ce pourrait être val ou chg) suivi du nom du champ capitalisé :

package geometrie;

class Point {
  private double x, y;

  Point() {}

  Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  void setX(double x) {
    this.x = x;
  }

  void setY(double y) {
    this.y = y;
  }

  void getX() {
    return x;
  }

  void getY() {
    return y;
  }
}

On doit alors remplacer, si p désigne un point :

Le fait de ne pas définir get... (resp. set...) interdit l'accès en lecture (resp. écriture). L'usage des méthodes d'accès permet également de contrôler la valeur des champs dans les cas où elle doit respecter certaines contraintes. Par exemple, si l'on sait qu'un champ numérique doit être compris entre deux valeurs champMIN et champMAX, la méthode setChamp s'assurera du respect de cette contrainte :

  private static double champMIN=0.0, champMAX=100.0;

  void setChamp(double champ) {
    if (champ < champMIN) 
      this.champ = champMIN;
    else if (champ > champMAX)
      this.champ = champMAX;
    else
      this.champ = champ;
  }

Comme autre exemple, il y a des situations où le nombre de fois qu'un champ est modifié doit être limité (par exemple, la zone d'un lecteur de DVD peut être changée au plus 5 fois) : un champ supplémentaire, évidemment privé, et initialisé implicitement à 0, permet de contrôler le nombre de modifications.

  private static final int N = 5;
  private int champModifié;

  void setChamp(int champ) {
    if (champModifié<N) 
      this.champ = champ;
      champModifié++;
  }

Tous ces exemples constituent des patterns, c'est-à-dire des solutions typiques à des problèmes qui se rencontrent fréquemment, et qui peuvent être adaptées à chaque problème. La discipline d'encapsulation consiste à rendre systématiquement les champs privés, et à fournir, selon les besoins, l'une ou l'autre des méthodes d'accès setXxx et getXxx à chaque champ xxx, selon le pattern souhaité :

En outre, si le type est rendu public, les méthodes d'accès doivent également être déclarées publiques. Par exemple, pour des champs en lecture seulement :

package geometrie;

public class Point {
  private double x, y;

  public Point() {}

  public Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  public void getX() {
    return x;
  }

  public void getY() {
    return y;
  }
}

3.4.0.0.1 Privatisation des méthodes et des constructeurs

Une méthode peut aussi être déclarée privée en faisant précéder sa déclaration du mot-clé private. Une méthode privée peut être invoquée à l'intérieur sa classe, mais pas par une méthode d'une autre classe. Un constructeur peut être déclaré privé et ne pourra pas figurer dans une expression d'instanciation en dehors de sa classe.


3.4.0.0.2 Patterns

Loin d'être simplement un nouveau langage, Java est au c\oeur d'une nouvelle technologie, qui se déploie à la fois de façon matérielle (futures cartes à puce, systèmes embarqués) et de façon logicielle sous forme d'API spécialisée (Application Programming Interface), par exemple pour l'accès aux bases de données, la programmation réseau ou pour le graphique. L'utilisation des APIs fait que de nombreuses applications traditionnellement difficiles à programmer deviennent très simples. Cependant, leur utilisation demande une certaine compréhension de leur organisation, qui résulte d'une part de traits du langage Java (les packages, les interfaces, les règles d'accessibilité, etc.) et d'autre part, de l'application systématique de certaines méthodes de conception, qui identifient des situations typiques et des façons de les aborder et de les résoudre. Le besoin de recourir à de telles méthodes de conception n'est pas propre à l'informatique. La notion de pattern a été développée à la fin des années 1970 par un architecte, Christopher Alexander, qui les définit ainsi :

«A pattern is a careful description of a perennial solution to a recurring problem within a building context, describing one of the configurations which brings life to a building.

A pattern language is a network of patterns that call upon one another. An individual house might, for example, call upon the patterns described under the names of half-hidden garden, light from two sides in every room, variation of ceiling height, bed alcove, etc. Patterns help us remember insights and knowledge about design and can be used in combination to create designs.»

Cette notion s'est vue réappropriée par des informaticiens, une dizaine d'années plus tard, et constitue actuellement l'une des approches les plus intéressantes de l'architecture des systèmes logiciels. Tant ces traits du langage que les patterns sont utiles à la programmation d'applications, pour peu que l'on s'efforce de les programmer proprement en respectant certains critères : indépendance de l'interface et de l'implémentation, facilité de modification ou de réutilisation, etc. Les choix que l'on fait quand on écrit un programme peuvent souvent se lire comme le choix d'un pattern contre un autre. En voici quelques autres : singleton, fabrication, itération, décoration, visitation (?), etc.


3.4.0.0.3 Un pattern de création : les classes singletons

Une classe singleton est une classe qui ne peut avoir qu'une seule instance. La réalisation d'une telle classe met en \oeuvre :

class Singleton {
  A champ;
  // ...
  private static Singleton instance;
  private Singleton(A champ) {
    this.champ = champ;
    // ...
  }
  // ...
  static Singleton uniqueInstance(A champ) {
    if (instance == null) {
      instance = new Singleton(champ);
    }
   return instance;
  }
}

Cette classe sera utilisée ainsi :

    Singleton s1 = Singleton.uniqueInstance(new Double(2.3));

Remarquons que si la méthode uniqueInstance n'est pas appelée, l'instance n'est pas créée : dans une application donnée, cette classe a au plus une instance, elle peut n'en avoir aucune.


3.4.0.0.4 Un pattern de création : les types d'énumération

Le recours à des variables de classe permet de définir des types d'énumération, c'est-à-dire comportant un nombre donné de constantes nommées. Par exemple, nous devons représenter l'état d'un feu tricolore par un type ayant exactement trois valeurs (rouge, orange, vert). Une solution est donnée par la classe suivante :

class Feu {
  static final Feu ROUGE = new Feu();
  static final Feu ORANGE = new Feu();
  static final Feu VERT = new Feu();

  private Feu() {}
}

Cette classe est conçue afin de vérifier les propriétés suivantes :


next up previous contents index
suivant: 3.5 Surcharge monter: 3. Classes d'objets précédent: 3.3 Membres statiques   Table des matières   Index
Rene' LALEMENT 2001-11-07