Médiaforma

All posts tagged interfaces

En programmation objet, les interfaces permettent d’indiquer quelles méthodes publiques une classe doit implémenter. Leur principal intérêt est de garantir que toutes les classes qui l’implémentent donneront accès aux méthodes spécifiées dans l’interface.

L’utilisation d’interfaces trouve son utilité dans des projets impliquant plusieurs programmeurs ou développés de façon modulaire.

Voyons comment mettre en œuvre une interface dédiée à la formation PHP. Les classes qui implémenteront cette interface devront elles-mêmes implémenter les méthodes publiques programme() et pratique().

Voici le fichier interface.php correspondant :

<?php
interface formationPHP{
  public function programme();
  public function pratique();
}
?>

Nous allons maintenant définir deux classes qui implémentent l’interface formationPHP.

Voici le code de la classe debutant (debutant.class.php) :

<?php
  require_once "interface.php";
  class debutant{
    public function programme() {
      return "<ul><li>Instructions</li><li>Fichiers</li><li>Transmission de données</li></ul>";
    }

    public function pratique() {
      return "Exercices pour appréhender le langage.<br>";
    }
  }
?>

Remarquez l’instruction require_once au début du listing, pour faire référence à l’interface.

Et voici le code de la classe avance (avance.class.php) :

<?php
  require_once "interface.php";
  class avance{
    public function programme() {
      return "<ul><li>Superglobales</li><li>POO</li><li>BDD</li></ul>";
    }

    public function pratique() {
      return "Nombreux exercices de tous niveaux.<br>";
    }
  }
?>

Il ne reste plus qu’à utiliser les classes debutant et avance en définissant un quatrième fichier PHP (formation.php) :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Utilisation des classes debutant et avance</title>
  </head>
  <body>
    <?php
      include_once("debutant.class.php");
      include_once("avance.class.php");
      $coursDebutant = new debutant;
      $coursAvance = new avance;
      echo "<b>Formation pour débutants PHP</b><br>";
      echo "<i>Programme :</i><br>";
      echo $coursDebutant->programme();
      echo "<i>Pratique :</i><br>";
      echo $coursDebutant->pratique();

      echo "<br><b>Formation avancée PHP</b><br>";
      echo "<i>Programme :</i><br>";
      echo $coursAvance->programme();
      echo "<i>Pratique :</i><br>";
      echo $coursAvance->pratique();
    ?>
  </body>
</html>

Les classes debutant et avancé sont incluses au début du script avec la fonction include_once.

Les objets $coursDebutant et $coursAvance sont alors créés en instanciant les classes debutant et avance.

Le texte Formation pour débutants est alors affiché en gras.

Puis le mot Programme est affiché en italique.

Pour obtenir le programme de la formation PHP pour débutants, on invoque la méthode programme de la classe coursDebutant. Les notions abordées dans le programme sont alors affichées, retournées par la méthode programme.

Le texte pratique est alors affiché en italique puis la méthode pratique de l’objet coursDebutant est invoquée pour afficher le type d’exercices effectués dans la formation débutant.

Des instructions du même type affichent le programme et le type d’exercices pratiqués dans la formation PHP avancée.

Exécutons ce code dans WAMP Server. Les méthodes programme et pratique des objets coursDebutant et coursAvance sont bien accesibles et retournent bien les informations attendues.


Considérez le code suivant :

public class GenericsTypeAvant {

    private Object t;
     public Object get() {
        return t;
    }

    public void set(Object t) {
        this.t = t;
    }

    public static void main(String args[]){
        GenericsTypeAvant type = new GenericsTypeAvant();
        type.set(12);
        String str = (String) type.get();
    }
}
Ce code se compile correctement, mais il produit une erreur CassCastException à l’exécution. En effet, le nombre 12 ne peut pas être casté en un String :

 

 

Considérez maintenant le code suivant :

public class GenericsTypeMaintenant<T> {

    private T;

    public T get(){
        return this.t;
    }

    public void set(T t1){
        this.t=t1;
    }

    public static void main(String args[]){
        GenericsTypeMaintenant<String> type = new GenericsTypeMaintenant<>(); // Type String
        type.set("chaîne"); // OK

        GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>(); //Type Integer
        type1.set(12); //OK
        //type1.set("abc"); //Invalide

        GenericsTypeMaintenant type2 = new GenericsTypeMaintenant(); //Type quelconque
        type2.set("texte"); //OK
        type2.set(10); //Valide

    }
}

Le type T est spécifié dans la classe :

public class GenericsTypeMaintenant<T>

Lors de l’instanciation d’un objet de classe GenericsTypeMaintenant, on définit le type de l’objet passé. Par exemple, un type String :

GenericsTypeMaintenant<String> type = new GenericsTypeMaintenant<>();

On passe alors un objet de type String au setter après l’instanciation de la classe :

type.set("chaîne");

Si on lui passe un autre type, une erreur sera déclenchée à la compilation.

Par exemple, cette instruction :

type.set(12);

Provoque une erreur à la compilation :

 

 

Lors de l’instanciation d’un objet GenericsTypeMaintenant, on peut aussi définir un type Integer :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();

 

Dans ce cas, les instructions suivantes ne produiront aucune erreur de compilation :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();
type1.set(12); //OK

 

Par contre, ces instructions provoqueront une erreur à la compilation :

GenericsTypeMaintenant<Integer> type1 = new GenericsTypeMaintenant<>();
type1.set("abc"); //Invalide

 

Si aucun type n’est spécifié :

GenericsTypeMaintenant type2 = new GenericsTypeMaintenant();

 

Une valeur de type quelconque peut être passée au setter. Ainsi, ces deux instructions sont correctes :

type2.set("texte");
type2.set(10);

Les interfaces sont essentiellement utilisées pour répertorier les méthodes qui doivent être définies dans les classes qui implémentent l’interface :

A titre d’exemple, créez le fichier Forme.java suivant :

package laForme;
public interface Forme {
  public float perimetre();
  public float surface();
}

Les classes Cercle.class et Rectangle.class vont implémenter cette interface. Voici le code de la classe Cercle.class :

package laForme;
public class Cercle implements Forme {
   private int rayon;

   public Cercle(int r) {
      this.rayon=r;
   }

   public float perimetre() {
      float resultat = 2 * (float)Math.PI * rayon;
      return resultat;
   }

   public float surface() {
      return (float)Math.PI * rayon * rayon;
   }

   public String toString() {
      return ("un cercle de rayon " + rayon);
   }
}

Et voici le code de la classe Rectangle.class :

package laForme;

public class Rectangle implements Forme {
  private int longueur, largeur;

  public Rectangle(int longueur, int largeur) {
    this.longueur = longueur;
    this.largeur = largeur;
  }

  public float perimetre() {
     return 2 * (longueur + largeur);
  }

  public float surface() {
     return longueur * largeur;
  }
}

Pour utiliser les classes Cercle et Rectangle, définissez la classe EssaiFormes comme ceci :

package laForme;
import java.lang.String;

public class EssaiFormes {
  public static void main(String[] arg) {
      Cercle = new Cercle(2);
      Rectangle = new Rectangle(2, 1);

      System.out.println("La surface d'un cercle de rayon 2 est " + cercle.surface());
      System.out.println("Le périmètre d'un cercle de rayon 2 est " + cercle.perimetre());
      System.out.println("La surface d'un rectangle de 2x1 est " + rectangle.surface());
      System.out.println("Le périmètre d'un rectangle de 2x1 est " + rectangle.perimetre());
  }
}

Vous allez maintenant compiler ces fichiers en utilisant le compilateur javac. Supposons que les fichiers java se trouvent dans le dossier c:\Users\Michel\Documents\NetBeansProjects\laForme. Créez un dossier laForme dans ce dossier.

Depuis le dossier c:\Users\Michel\Documents\NetBeansProjects\laForme, lancez la commande suivante :

c:\Users\Michel\Documents\NetBeansProjects\laForme>javac Forme.java

Cette commande crée le fichier Forme.class. Placez ce fichier dans le sous-dossier laForme\laForme puis lancez les commandes suivantes :

c:\Users\Michel\Documents\NetBeansProjects\laForme>javac Cercle.java
c:\Users\Michel\Documents\NetBeansProjects\laForme>javac Rectangle.java

Placez les fichiers Cercle.class et Rectangle.class dans le sous-dossier laForme/laForme puis lancez la commande suivante :

c:\Users\Michel\Documents\NetBeansProjects\laForme>javac EssaiFormes.java

Placez le fichier EssaiFormes.class dans le dossier laForme/laForme puis lancez la commande suivante :

c:\Users\Michel\Documents\NetBeansProjects\laForme>java laForme/EssaiFormes

Voici le résultat :