Logo ConstructiCat
CodeBust.
Parcourir la section ▾

Interface surchargée.

L’interface surchargée est un antipatron où une seule interface accumule tant d’opérations que chaque client dépend de méthodes qu’il n’utilise jamais.

Une interface surchargée (en anglais interface bloat) est un antipatron dans lequel une seule interface – l’API publique d’une classe, une interface Java ou C#, les fonctions exportées d’un module – accumule bien plus d’opérations que n’en a besoin chacun de ses clients.

Définition

Le terme « bloat » (gonflement) désigne plusieurs problèmes de conception logicielle, dont les interfaces utilisateur encombrées de fonctions et d’options. En conception d’API, une interface est surchargée lorsqu’elle regroupe derrière un même type plusieurs responsabilités sans rapport : recherche, persistance, administration, notifications. Chaque implémentation doit alors toutes les fournir, et chaque client dépend d’opérations qu’il n’appelle jamais ; la moindre modification de l’une d’elles oblige à recompiler, retester ou redéployer des clients qui ne sont pas concernés.

Signes typiques d’une interface surchargée :

  • des implémentations qui laissent des méthodes vides ou lèvent UnsupportedOperationException ;
  • des doublures de test qui doivent simuler une douzaine de méthodes pour un test qui n’en utilise qu’une ;
  • des groupes de méthodes utilisés par des clients différents et qui évoluent pour des raisons différentes.

Principe de ségrégation des interfaces

Le remède est le principe de ségrégation des interfaces (le « I » de SOLID) : aucun client ne doit être forcé de dépendre de méthodes qu’il n’utilise pas. L’interface surchargée est découpée en plusieurs petites interfaces, chacune dédiée à un rôle. Une même classe peut toujours les implémenter toutes, mais chaque client ne voit que le rôle dont il a besoin.

Le refactoring Extraire l’interface est généralement la première étape. Une interface surchargée recouvre souvent un God object ou une classe trop volumineuse, qu’il faut alors découper aussi.

Exemple

Ce UserRepository mélange recherches, persistance, requêtes d’administration et e-mails de réinitialisation du mot de passe. Une page de profil qui n’appelle que byId dépend malgré tout des sept méthodes, et chaque faux objet de ses tests doit les implémenter.

interface UserRepository {
    User byId(int id);
    User byEmail(String email);
    void save(User user);
    void delete(int id);
    void rename(int id, String name);
    List<User> admins();
    void sendReset(int id);
}

Une fois découpée par rôle, chaque client ne dépend que de ce qu’il appelle :

interface UserLookup {
    User byId(int id);
    User byEmail(String email);
    List<User> admins();
}

interface UserStore {
    void save(User user);
    void delete(int id);
    void rename(int id, String name);
}

interface PasswordReset {
    void sendReset(int id);
}

class ProfilePage {
    private final UserLookup users; // ne dépend que de ce qu’elle utilise

    ProfilePage(UserLookup users) { this.users = users; }

    String title(int id) { return users.byId(id).name(); }
}

Une seule classe JdbcUsers peut toujours implémenter UserLookup et UserStore ; seules les dépendances des clients ont diminué.

Adapté de l’article Wikipédia “Interface bloat” (révision 1304469164), disponible sous licence CC BY-SA 4.0 ; le texte a été traduit et modifié, et des exemples ont été ajoutés.