• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Ce cours est en vidéo.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Mis à jour le 12/10/2018

Concevez une interface

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Maintenant que vous comprenez le principe d'héritage et de polymorphisme, nous allons voir le concept de contrat au travers des interfaces.

Un contrat

Qu'est-ce qu'un contrat ?

Pour faire simple, on peut dire que c'est un accord entre plusieurs parties : "J'effectue telle action pour toi. En contrepartie, tu effectues telle action pour moi."

En développement, ce concept se représente via une interface. Quand vous travaillez avec d'autres développeurs, vous avez des interactions. Vous allez souvent vous retrouver en train de dire : "Tiens, je passe tel paramètre à ta méthode ; elle doit faire ça pour moi."

Un exemple plus concret :

  • j'ai une classe  Parisien, qui représente un Parisien ;

  • je souhaite ajouter une méthode  seDeplacer ;

  • en paramètre j'ai besoin d'un moyen de locomotion ;

  • la seule chose dont je veux m'assurer, c'est que ce moyen de locomotion possède une méthode  deplace  qui prend en paramètre une  adresse  de type  String .

Une interface va nous aider à répondre à ce type de problème :

package com.cursan.paris;

public class Parisien {
    public void seDeplacer(MoyenDeLocomotion moyenDeLocomotion) {
        moyenDeLocomotion.deplace("19 rue Germain Pilon 75018 Paris");
    }
}
package com.cursan.paris;

public interface MoyenDeLocomotion {
    void deplace(String adresse);
}

Niveau syntaxe, c'est super simple ! On remplace  class  par  interface  et on ajoute des méthodes sans comportement.

Mais alors, comment les autres développeurs vont-ils pouvoir se servir de notre interface ? Grâce au mot clé   implements.

package com.cursan.homeshop;

public class Bus implements MoyenDeLocomotion {
    @Override
    public void deplace(String adresse) {
        System.out.println("Je suis un bus et je vais à l'adresse " + adresse);
    }
}
package com.cursan.homeshop;

public class Taxi implements MoyenDeLocomotion {

    @Override
    public void deplace(String adresse) {
        System.out.println("Je suis un taxi et je vais à l'adresse : " + adresse);
    }
}

Quand on utilise  implements , Java nous oblige à  Override  chaque méthode de l'interface.

Le code suivant fonctionne sans problème :

public static void main(String[] args) {
    Parisien segolene = new Parisien();
    
    Bus bus = new Bus();
    segolene.seDeplacer(bus);
    Taxi taxi = new Taxi();
    segolene.seDeplacer(taxi);
    MoyenDeLocomotion taxi2 = new Taxi();
    segolene.seDeplacer(taxi2);
}

La méthode  seDeplacer  demande un paramètre de type  MoyenDeLocomotion.  bus  ,  taxi  et  taxi2  sont de type  MoyenDeLocomotion .

Quand deux classes interagissent entre elles, c'est important de toujours réfléchir en termes de contrat. Cela permet de limiter les interactions et d'avoir un code plus flexible.

Conception de la livraison

Nous allons ajouter un système de livraison à notre application. Pour chaque facture, nous aurons un moyen de livraison associé parmi les suivants :

  • Livraison à domicile 

  • Livraison à domicile express 24h

  • Livraison en point relais

  • Retrait gratuit à l'entrepôt dans Paris

Pour chaque moyen de livraison, la seule chose qui nous intéresse est de connaître le prix. Il y a certaines règles un peu compliquées à mettre en place :

  • Pour la livraison à domicile, le prix est toujours le même : 4.99€.

  • Pour la livraison à domicile express, le prix est de 6.99€ à Paris. En dehors de Paris, c'est 9.99€.

  • Les points relais sont identifiés par un numéro. Les numéros de 1 à 22 sont gratuits. Les numéros de 23 à 47 sont à 2.99€. Les autres sont à 4.99€.

Pour l'UML, nous allons utiliser une interface.  Bill  contiendra un attribut de cette interface.

UML Livraison
UML Livraison

Implémentation de la livraison

ExpressDelivery  et  RelayDelivery  possèdent de la logique. On commence donc par rédiger des tests.

package com.cursan.homeshop;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class RelayDeliveryTest {

    @Test
    public void Given_FreeRelay_WhenGettingDeliveryPrice_ThenGet0e() {
        Delivery delivery = new RelayDelivery(5);
        assertEquals(0.0, delivery.getPrice(), 0.01);
    }

    @Test
    public void Given_LowPriceRelay_WhenGettingDeliveryPrice_ThenGet2e99() {
        Delivery delivery = new RelayDelivery(27);
        assertEquals(2.99, delivery.getPrice(), 0.01);
    }

    @Test
    public void Given_HighPriceRelay_WhenGettingDeliveryPrice_ThenGet4e99() {
        Delivery delivery = new RelayDelivery(52);
        assertEquals(4.99, delivery.getPrice(), 0.01);
    }

}

À quoi sert le dernier paramètre 0.01 ? C'est une question de précision. Cela permet de préciser qu'il faut comparer jusqu'à 2 chiffres après la virgule.

package com.cursan.homeshop;


import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ExpressDeliveryTest {
    @Test
    public void Given_RegionCityAsLocation_WhenGettingDeliveryPrice_ThenGet9e99() {
        Delivery delivery = new ExpressDelivery("Bordeaux");
        assertEquals(9.99, delivery.getPrice(), 0.01);
    }
    @Test
    public void Given_ParisAsLocation_WhenGettingDeliveryPrice_ThenGet6e99() {
        Delivery delivery = new ExpressDelivery("Paris");
        assertEquals(6.99, delivery.getPrice(), 0.01);
    }
}

Et voici le code des différentes interfaces et classes :

package com.cursan.homeshop;

public interface Delivery {
    public double getPrice();
}

Pour pouvoir créer une interface dans IntelliJ, il faut choisir "Interface" dans le menu pour créer une classe :

Création Interface
Création Interface
package com.cursan.homeshop;

public class DirectDelivery implements Delivery {
    @Override
    public double getPrice() {
        return 4.99;
    }
}
package com.cursan.homeshop;

public class RelayDelivery implements Delivery {
    private int number;

    public RelayDelivery(int number) {
        this.number = number;
    }

    @Override
    public double getPrice() {
        if (number >= 1 && number <= 22)
            return 0;
        else if (number >= 23 && number <= 47)
            return 2.99;
        else
            return 4.99;
    }
}
package com.cursan.homeshop;

public class ExpressDelivery implements Delivery {
    private String city;

    public ExpressDelivery(String city) {
        this.city = city;
    }

    @Override
    public double getPrice() {
        if (city.equals("Paris"))
            return 6.99;
        else
            return 9.99;
    }
}
package com.cursan.homeshop;

public class TakeAwayDelivery implements Delivery {
    @Override
    public double getPrice() {
        return 0;
    }
}
package com.cursan.homeshop;

import java.util.HashMap;
import java.util.Map;

public class Bill {
    private Client client;
    private Map<Product, Integer> products = new HashMap<Product, Integer>();
    private Delivery delivery;

    public Bill(Client client, Delivery delivery) {
        this.client = client;
        this.delivery = delivery;
    }

    public void addProduct(Product product, int quantity) {
        this.products.put(product, quantity);
    }

    public Client getClient() {
        return client;
    }

    public Map<Product, Integer> getProducts() {
        return products;
    }
}

Et voilà notre système pour la livraison est prêt !

Dans le prochain chapitre, nous allons générer notre facture.

Exemple de certificat de réussite
Exemple de certificat de réussite