Styles de programmation Java

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.

Style procédural

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") ;
    // ...
  }
}

Style objet

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") ;
    // ...
  }
}

Style objet, basé sur des fonctions de style procédural

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") ;
    // ...
  }
}

Syle mono-classe

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") ;
    // ...
  }
}

Style tout permis

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") ;
    // ...
  }
}