Aller au contenu principal

Interfaces en C#

Note : publié initialement le 29/10/2021

Les interfaces décrivent ce que doit contenir une classe, alors que les jeux de tests sont plutôt une vérification de son bon fonctionnement. Les interfaces permettent de définir les bases d'un programme, les plans de fonctionnement, alors que les tests vont permettre de s'assurer de ce bon fonctionnement.

Créer une interface en C# : un élément d'architecture du programme

En créant une interface, nous allons indiquer qu'une classe ou une structure doit fournir certaines choses. La documentation C# officielle parle de « contrat », et c'est bien ce qu'est une interface : on oblige une classe ou une structure de contenir certaines choses, si elle hérite de notre interface.

Nous créons donc un « patron » de conception d'une classe, sans définir la classe en lui-même. On saura ainsi de quelle manière on peut utiliser les classes qui sont faites avec ce patron. Typiquement, dans une équipe, vous pouvez avoir un architecte qui fait le design du logiciel, et d'autres personnes qui s'occupent de bâtir les fonctions.

Pour l'exemple, imaginons une implémentation de véhicule. Toute classe de notre programme qui implémente cette classe doit avoir une méthode pour entrer et sortir du véhicule, une méthode pour modifier la vitesse (accélération ou réduction), et des informations comme le nombre de personnes .

interface IVehicle
{
public int CharactersInside { get; }
public int Capacity { get; }
public void EnterVehicle(object character, bool forceExit);
public void ExitVehicle(object character);
public void ChangeSpeed(float speed);
}

Notez que nous l'avons appelé IVehicle. Le I majuscule au début du nom est une convention de nommage pour les interfaces, et les interfaces bénéficient d'une coloration syntaxique différente.

Ensuite, pour qu'une classe implémente cette interface, nous utilisons le symbole : au début du définition de la classe (comme pour un héritage).

class Car : IVehicle
{
// Car implémente l'interface IVehicle
}

Un gros avantage d'un IDE comme Visual Studio 2019, c'est qu'il permet de gérer facilement l'implémentation d'interface. En faisant une classe vide et en lui demandant d'implémenter IVehicle, on a l'erreur suivante, et Visual Studio propose de faire une implémentation par défaut (en écrivant les méthodes et propriétés, avec des exceptions « Non implémentées).

Visual Studio propose d'implémenter lui-même les membres d'interface

On peut alors remplacer les exceptions System.NotImplementedException(); par nos propres implémentations, et garder par exemple celles qui ne sont pas encore prêtes :

class Car : IVehicle
{
private List<object> charactersInCar = new List<object>();
public int CharactersInside => charactersInCar.Count();
public int Capacity => capacity;
private int capacity = 4;

public void ChangeSpeed(float speed)
{
throw new System.NotImplementedException();
}
public void EnterVehicle(object character, bool forceExit)
{
if(CharactersInside <= capacity || forceExit)
{
charactersInCar.RemoveAt(0);
charactersInCar.Add(character);
}
}
public void ExitVehicle(object character)
{
charactersInCar.Remove(character);
}
}

Une classe peut implémenter plusieurs interfaces

Une dernière chose concernant les interfaces : une classe peut hériter d'une autre classe, et en même temps implémenter une ou plusieurs interfaces. Dans ce cas, dans la déclaration de la classe, on indique d'abord la classe parente, puis les interfaces.

Par exemple, pour un personnage non joueur, notre classe Shopkeeper qui hérite de la classe Character et qui implémente les interface IInteractable (pour pouvoir discuter avec lui) et IFightable (pour que le système de combat fonctionne avec le personnage), la fonction code sera comme ainsi :

class Shopkeeper : Character, IInteractable, IFightable
{
// Le Shopkeeper est un personnage (hérite de Character) et implémente deux interfaces.
}

L'interface permet de définir comment on peut communiquer avec une classe (« une porte a une poignée »), (« si j'envoie ces deux entiers à une méthode nommée foo, elle me renvoie un booléen »), mais pas de tester si les fonctions envoient un résultat correct ou se comporte comme voulu. Pour ça, il y a les tests, décrits dans l'article Jeux de test en C#