On énumère quelques styles de programmation avec lesquels on peut réaliser tout programme dont le source tient en un unique fichier. On montre un exemple, avec un programme de manipulation de pile au moyen d'une liste chaînée.
La classe principale, du nom du fichier, contient des
champs statiques (utilisés comme variables globales du
programme) et des méthodes statiques (qui sont l'équivalent
des fonctions et procédures). C'est bien sûr elle qui
contient la méthode main
.
Les autres classes sont des définitions de structures,
sans aucune méthode et avec des champs dynamiques.
On ne crée jamais d'objet dont le type est la classe
principale.
// la pile vide est représentée par un Wagon qui vaut null class Wagon { int haut ; Wagon suite ; Wagon (int element, Wagon old) { haut = element ; suite = old ; } } public class Pile { static Wagon push (Wagon pile, int element) { return new Wagon (element, pile) ; } static int top (Wagon pile) { return pile.haut ; // NullPointerException si pile vide } static Wagon pop (Wagon pile) { return pile.suite ; // NullPointerException si pile vide } public static void main (String[] args) { Wagon p = null; p = push (p, 212) ; p = push (p, 13) ; if (top (p) != 13) System.out.println ("Catastrophe, y a un bug !\n") ; p = pop (p) ; if (top (p) != 212) System.out.println ("Catastrophe, y a un bug !\n") ; // ... } }
La classe principale, du nom du fichier,
ne contient que la méthode main
.
Les autres classes définissent des objets,
dont les champs et les méthodes sont dynamiques.
Il n'y a donc aucune méthode statique autre
que main
.
On ne crée jamais d'objet dont le type est la classe
principale.
// la pile vide est représentée par un Pile qui contient un Wagon qui vaut null class Wagon { int haut ; Wagon suite ; Wagon (int element, Wagon old) { haut = element ; suite = old ; } } class Pile { Wagon pile ; Pile () { pile = null; } void push (int element) { pile = new Wagon (element, pile) ; } int top () { return pile.haut ; // NullPointerException si pile vide } void pop () { pile = pile.suite ; // NullPointerException si pile vide } } public class Programme { public static void main (String[] args) { Pile p = new Pile (); p.push (212) ; p.push (13) ; if (p.top () != 13) System.out.println ("Catastrophe, y a un bug !\n") ; p.pop () ; if (p.top () != 212) System.out.println ("Catastrophe, y a un bug !\n") ; // ... } }
En interne, les méthodes sont de style procédural, mais on définit aussi des méthodes de styles objet :
// la pile vide est représentée par un Pile qui contient un Wagon qui vaut null class Wagon { int haut ; Wagon suite ; Wagon (int element, Wagon old) { haut = element ; suite = old ; } } public class Pile { Wagon pile ; static Wagon push (Wagon pile, int element) { return new Wagon (element, pile) ; } static int top (Wagon pile) { return pile.haut ; // NullPointerException si pile vide } static Wagon pop (Wagon pile) { return pile.suite ; // NullPointerException si pile vide } Pile () { pile = null; } void push (int element) { pile = push (pile, element) ; } int top () { return top (pile) ; } void pop () { pile = pop (pile) ; } } public class Programme { public static void main (String[] args) { Pile p = new Pile (); p.push (212) ; p.push (13) ; if (p.top () != 13) System.out.println ("Catastrophe, y a un bug !\n") ; p.pop () ; if (p.top () != 212) System.out.println ("Catastrophe, y a un bug !\n") ; // ... } }
On se limite à la définition d'une seule classe,
du nom du fichier, qui contient la méthode
main
.
Contrairement aux deux précédents, on peut créer
un objet dont le type est cette classe principale.
C'est même nécessaire dès qu'on doit utiliser des
structures chaînées.
On se limite aux méthodes statiques et aux
champs dynamiques.
Ce style de programmation est à mon avis le plus
obscur. Il présente la particularité de fabriquer
un unique fichier .class
!
// la pile vide est représentée par un Pile qui vaut null public class Pile { int haut ; Pile suite ; Pile (int element, Pile old) { haut = element ; suite = old ; } static Pile push (Pile pile, int element) { return new Pile (element, pile) ; } static int top (Pile pile) { return pile.haut ; // NullPointerException si pile vide } static Pile pop (Pile pile) { return pile.suite ; // NullPointerException si pile vide } public static void main (String[] args) { Pile p = null; p = push (p, 212) ; p = push (p, 13) ; if (top (p) != 13) System.out.println ("Catastrophe, y a un bug !\n") ; p = pop (p) ; if (top (p) != 212) System.out.println ("Catastrophe, y a un bug !\n") ; // ... } }
Chaque classe peut contenir des méthodes et des champs statiques ou dynamiques, indifféremment... C'est le bordel si on ne fait pas ça proprement.
// la pile vide est représentée par un Pile qui vaut null public class Pile { int haut ; Pile suite ; static Pile pileDeBase = null ; Pile (int element, Pile old) { haut = element ; suite = old ; } static Pile push (Pile pile, int element) { return new Pile (element, pile) ; } int top () { // NullPointerException si pile vide return haut ; } Pile pop () { // NullPointerException si pile vide return suite ; } public static void main (String[] args) { pileDeBase = push (pileDeBase, 10) ; if (pileDeBase.top () != 10) System.out.println ("Catastrophe, y a un bug !\n") ; // ... } }