Rechercher
 

Les niveaux d'accès en Java

Les packages La généricité en Java



Nous allons au cours de ce chapitre étudier un concept de la programmation orientée objet que nous n'avions pas pu aborder auparavant : l'encapsulation des membres (ou champs) d'une classe. En effet, comme la notion de package y joue une rôle important, nous devions donc l'étudier. Ceci étant fait, nous sommes donc près pour ce nouveau chapitre.

L'encapsulation.

L'encapsulation permet de montrer d'une classe, uniquement ce qui est nécessaire pour son utilisation : nous nommerons cet ensemble interface publique de la classe (attention à ne pas confondre le mécanisme d'interface Java avec l'interface publique d'une classe). Cette interface publique contient l'ensemble des attributs et des méthodes utilisables de l'extérieur sur des objets instanciés sur la classe considérée. En fait, c'est un peu plus compliqué qu'il n'y parait. Il existe plusieurs niveaux de visibilité utilisable sur les champs (les membres) d'une classe, et parfois, il n'est pas trivial pour le concepteur de fixer ces niveaux. Pour parler de ces niveaux de visibilité, on parle parfois d'attributs de visibilités : encore une fois, il ne faut pas les confondre avec les attributs de classe. Etudions donc chacun de ces niveaux de visibilité.

L'accès public.

Cette accès est le plus général et le moins contraignant. En effet, si un champ d'une classe est déclaré comme étant publique, alors tout objet ayant une référence sur un objet de cette même classe pourra accéder à ce champs (et éventuellement le modifier).

 
class A {
    public int a=0;
}

class Main {
    public static void main(String args[]){
        A a=new A();
        a.a++;
    }
}

L'accès private.

En définissant un champ d'une classe privée, vous interdisez tous les accès extérieurs. Seules les autres méthodes de la classe pourront utiliser ce champ. Attention, même les méthodes d'une classe fille ne peuvent accéder un champ privé d'une classe.

 
class A {
    public int a=0;
    static private b=0;
}

class Main extends A {
    public static void main(String argv[]){
        A a=new A();
        a.a++;       // Marche très bien

        // a.b++;    // Ne marche pas
        // b++;      // Ne marche pas non plus
  }
}

On trouve deux principaux avantages à utiliser cet genre d'accès. Tout d'abord, il y a des situations ou des champs d'une classe n'existent que pour le fonctionnement de celle-ci, mais que vous ne vouliez surtout pas qu'un utilisateur de cette dernière y ai accès : il suffit dans ce cas de fixer ces champs comme étant private.

Le deuxième avantage relève de la robustesse de votre code. En effet, on peut imaginer des situations ou un attribut de classe ne puisse pas prendre certaines valeurs (par exemple, l'attribut denominator d'une classe Rational ne peut en aucun cas valoir 0). Dans un tel cas, laisser l'attribut public peut être dangereux pour une bonne exécution du code de vos classes : l'utilisateur peut à tout moment affecter une valeur fatale. Une solution est de placer de tels attributs en accès private et de fournir, pour chaque champ, une méthode de lecture, et une d'écriture. Dès lors, la méthode de modification peut contrôler la bonne validité de la valeur que l'on souhaite affecter. L'exemple suivant montre ce que pourrait être une classe Rational robuste.

 
class Rational {
    private int numerator = 0;
    private int denominator = 1;

    public int getNumerator(){ return numerator; }

    public void setNumerator(int value){ numerator=value; }

    public int getDenominator(){ return denominator; }

    public void setDenominator(int value){
        if (value==0) {
            System.err.println("Bad denominator value : " + value);
            System.exit(-1);
        }
        denominator=value;
    }
}

En regardant bien ce petit programme, on peut encore tirer quelques remarques. Ce genre de programmation permet, pour l'utilisateur de la classe de faire abstraction de la manière dont le problème est résolu (l'utilisateur n'a peut-être pas envie de savoir qu'en fait un rationnel est représenté par deux int). Autre petite chose peut-être moins visible, la maintenance de ce genre de programmes est plus aisée (l'expérience vous permettra sans doute de confirmer cette dernière remarque).

L'accès protected.

L'accès protégé (protected en anglais) est en fait un hybride des deux accès précédents. Un champ ainsi déclaré pourra, selon les situations, tantôt être considéré comme public, tantôt comme privé. Plus exactement, un champ protégé sera considéré comme public pour toutes les méthodes de la classe, ainsi que pour toutes celles des sous-classes de celle considéré. Ce même champ sera de plus considéré public par toutes les méthodes du package contenant la classe susmentionnée. Dans tous les autres cas d'accès, un champ protégé sera considéré comme privé et donc non accessible. Le petit exemple suivant illustre ce qui vient d'être dit.

L'accès friendly.

Il s'agit de l'accès par défaut. Dans ce cas là, le champs sera public vis à vis du package, et privé pour le reste. Pensez toujours à une chose, toute classe appartient au moins à un package : Il existe aussi un package par défaut.

Quelques conventions.

Nous allons dès maintenant tenter d'établir un certain nombre de règles de programmation. Même si celles-ci vous semblent inutiles pour le moment, sachez, que par la suite, elles prendront une réelle importance, et notamment avec la programmation orientée composants. Vous pouvez bien sûr choisir de les ignorer : il ne s'agit que de conventions. Cependant, sachez qu'elle assure un style propre, et permettent un grand nombre de choses. Pour preuve, sachez que toutes les classes fournies en standard avec le JDK, respectent ces conventions.

La première règle impose que tout attribut de classe doit être déclaré private. Cela implique que vous ne puissiez l'accéder que par des méthodes spécialisées. Une conséquence évidente, est que si des valeurs de cet attribut peuvent nuire à l'application, alors, les méthodes de modification pourront vérifier que l'on ai pas à affecter ces valeurs.

La méthode d'affectation de l'attribut doit respecter le prototype suivant, en supposant que votre attribut se nomme attr, et soit de type type.

 
void setAttr(type value)

La méthode de consultation doit elle aussi respecter le prototype suivant :

 
type getAttr()

En conclusion.

Quoi qu'il en soit, vous avez tout intérêt à utiliser l'encapsulation. En effet, il en résulte trois avantages principaux - l'utilisation des objets (instances de la classe) en est simplifiée - le programme peut être plus robuste - la maintenance de la classe en est plus aisée.



Les packages La généricité en Java