0 votes

Orienté Objet - Où placer cette Déclaration d'Interface

J'ai quelques questions pour vous, sages personnes, concernant la conception orientée objet avec des Interfaces et des classes abstraites. Considérez le scénario suivant :

J'ai une classe de base abstraite "DataObjectBase" et une classe dérivée "UserDataObject." J'ai aussi une interface "IDataObject." L'interface expose bien sûr toutes les méthodes et propriétés publiques que mes objets de données doivent exposer, et vous pouvez probablement deviner que la classe de base abstraite implémente les méthodes et propriétés communes à tous les objets de données.

Ma question est, si la classe de base abstraite DataObjectBase implémente tout ce qui est spécifié dans l'interface IDataObject, l'interface doit-elle être déclarée dans la classe de base ou dans la classe(s) dérivée(s) ?

En C#, les interfaces déclarées dans la classe de base sont implicitement appliquées aux classes dérivées, mais est-ce la meilleure pratique ? Il me semble que implémenter l'interface dans la classe de base rend moins évident que la classe dérivée implémente l'interface, mais cela nécessite alors que l'interface soit spécifiée pour chaque classe dérivée.

De plus, si la classe de base n'était PAS abstraite, la recommandation changerait-elle ?

Une deuxième sous-question : Si la classe de base implémente toutes les méthodes/propriétés de l'interface IDataObject, l'interface est-elle même nécessaire ? Le nom de la classe de base peut simplement être utilisé à la place du nom de l'interface, par exemple :

private DataObjectBase _dataObject;
private IDataObject _dataObject;

Dans l'exemple ci-dessus (où la classe de base implémente tout ce que l'interface expose), les deux peuvent être affectés aux mêmes types dérivés. Personnellement, j'utilise toujours l'interface dans ces situations, mais je suis intéressé par les opinions des gens.

Merci d'avance.

1voto

cjk Points 27463

Si vos classes utilisateur hériteront toujours d'une classe de base, alors vous n'avez pas besoin de l'interface. S'il existe une possibilité que vous ayez des classes qui correspondent à l'interface mais qui ne dérivent pas de la classe de base, alors utilisez l'interface.

Quant à l'interface étant cachée dans la classe de base et donc pas immédiatement visible dans la classe utilisateur, c'est normal et peut être géré par le compilateur. C'est également là que les bonnes conventions de nommage entrent en jeu - votre UserDataObject a un nom qui correspond à IDataObject, tout comme DataObjectBase. Vous pourriez ajouter un commentaire au fichier de classe qui dit qu'il hérite de IDataObject, mais il sera visible qu'il hérite de DataObjectBase, qui à son tour semble hériter de IDataObject par son nom.

1voto

djna Points 34761

Ma façon de penser à propos de tels problèmes est de considérer les différentes personnes lisant le code, les "rôles" si vous préférez. Pensez également à la maintenabilité globale du système.

Tout d'abord, il y a du code qui s'attend à utiliser l'Interface. Il est écrit en termes de l'interface, l'auteur n'a (ou du moins ne devrait pas avoir) aucun intérêt pour l'implémentation. C'est pourquoi nous fournissons la classe Interface. De ce point de vue, la Classe de Base Abstraite n'est qu'une parmi de nombreuses hiérarchies d'implémentation possibles. Ne parlez pas à ce rôle de détails d'implémentation. Gardez l'Interface.

Ensuite, nous avons le rôle qui conçoit une implémentation. Ils trouvent une approche possible et découvrent quelques variations, donc ils veulent regrouper du code commun. Classe de Base Abstraite - remplissez les parties communes ici, laissez les implémenteurs détaillés remplir les zones vides. Aidez-les en fournissant des méthodes abstraites disant "votre code va ici". Notez que ces méthodes ne doivent pas seulement être celles de l'Interface. Notez également que cette Classe de Base Abstraite pourrait même implémenter plus d'une Interface! (par exemple. C'est TravailleurIntelligent mais aussi un PersisterTravailIntermédiaire.)

Ensuite, nous avons le rôle qui fait réellement l'implémentation détaillée. Remplissez les parties vides ici. Très facile à comprendre. Dans ce cas, vous n'avez même pas besoin de considérer l'Interface en tant que telle. Votre travail est de rendre cette classe abstraite concrète.

En fin de compte ... j'utilise à la fois des Interfaces et des classes de Base. Vous mettez l'Interface sur la Classe de Base. Nous n'ajoutons pas de valeur en l'ajoutant à la classe d'implémentation.

0voto

belugabob Points 2966

L'autre chose qui doit être mentionnée est que l'utilisation des interfaces rend plus facile la mise en œuvre de tests automatisés.

Disons, par exemple, qu'une des méthodes de l'interface est censée générer une exception - comme 'DatabaseConnectionLostException' - et que vous voulez tester le code client pour vérifier qu'il se comporte correctement dans une telle situation.

Il est simple de fournir une implémentation de l'interface qui génère l'exception, permettant ainsi d'écrire le test.

Si vous aviez utilisé la classe de base abstraite au lieu de l'interface, cette opération serait beaucoup plus compliquée (OK, vous pouvez utiliser des Mocks, mais la solution avec l'interface est beaucoup plus propre)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X