Interface ou classe abstraite?

Pour mon nouveau projet Pet, j’ai une question de design, c’est déjà décidé, mais je veux aussi d’autres opinions à ce sujet.

J’ai deux classes (simplifiées):

class MyObject { ssortingng name {get;set;} enum relation {get;set;} int value {get;set;} } class MyObjectGroup { ssortingng name {get;set;} enum relation {get;set;} int value {get;set;} List myobjects {get;set;} } 

Plus tard dans le projet, MyObjectGroup et MyObject doivent être utilisés également. Pour cela, je pourrais aller de deux manières:

  • Créer une interface: IObject
  • Créer une classe abstraite: ObjectBase

J’ai décidé de suivre le chemin de l’interface, c’est-à-dire que plus tard dans le code, je ne dois pas écrire ObjectBase chaque fois, mais IObject simple facilité – mais quels sont les autres points positifs de cette façon?

Et deuxièmement, qu’en est-il d’append IXmlSerializable à l’ensemble de l’histoire? Laissez l’interface hériter de IXmlSerializable ou a-t-elle plus de points positifs pour implémenter IXmlSerializable dans une classe de base abstraite?

De manière générale, l’approche que j’utilise dans ce genre de situation est d’avoir à la fois une interface et une classe abstraite. Les interfaces définissent bien l’interface. La classe abstraite est simplement une aide.

Vous ne pouvez vraiment pas vous tromper avec cette approche. Les interfaces vous permettent de changer d’implémentation. Les classes abstraites vous donnent le code standard et le code d’assistance que vous n’êtes pas obligé d’utiliser, ce qui serait le cas si vos méthodes étaient définies explicitement en termes de classe abstraite.

Voici quelques unes des différences entre les classes Interfaces et Abstract.

1A. Une classe peut hériter (implémenter) d’une ou plusieurs interfaces. Donc, en C #, les interfaces sont utilisées pour obtenir un inheritance multiple.
1B. Une classe ne peut hériter que d’une classe abstraite.

2A. Une interface ne peut fournir aucun code, juste la signature.
2B. Une classe abstraite peut fournir un code complet par défaut et / ou uniquement les détails à remplacer.

3A. Une interface ne peut pas avoir de modificateurs d’access pour les sous-programmes, fonctions, propriétés, etc. Tout est supposé public.
3B. Une classe abstraite peut contenir des modificateurs d’access pour les sous-fonctions, fonctions et propriétés.

4A. Les interfaces sont utilisées pour définir les capacités périphériques d’une classe. Pour par exemple. Un Ship et une Car peuvent implémenter une interface IMovable .
4B. Une classe abstraite définit l’identité principale d’une classe et est utilisée pour les objects.

5A. Si différentes implémentations ne partagent que des signatures de méthodes, il est préférable d’utiliser des interfaces.
5B. Si différentes implémentations sont du même type et utilisent un comportement ou un statut commun, il est préférable d’utiliser une classe abstraite.

6A. Si nous ajoutons une nouvelle méthode à une interface, nous devons localiser toutes les implémentations de l’interface et définir celle de la nouvelle méthode.
6B. Si nous ajoutons une nouvelle méthode à une classe abstraite, nous avons la possibilité de fournir une implémentation par défaut. Par conséquent, tout le code existant peut fonctionner correctement.

7A. Une interface ne peut pas avoir de champs définis.
7B. Une classe abstraite peut avoir des champs et des constantes définis.

8A. Une interface ne peut pas avoir de constructeur.
8B. Une classe abstraite peut avoir des constructeurs par défaut implémentés.

9A. Une interface ne peut hériter que d’autres interfaces.
9B. Une classe abstraite peut hériter d’interfaces, de classes abstraites ou même de classes.

L’interface serait ma valeur par défaut jusqu’à ce qu’il y ait une raison d’utiliser une classe de base, car elle prend moins de décisions pour nous.

Je n’impliquerais pas IXmlSerializable sauf si je devais le faire; c’est une interface compliquée et compliquée, souvent source de problèmes.

Quelles sont exactement vos exigences de sérialisation? Il peut y avoir de meilleures options … Cependant, pour de nombreux sérialiseurs, une classe de base serait plus facile qu’une interface. Par exemple, pour XmlSerializer vous pourriez avoir:

 [XmlInclude(typeof(MyObject))] // : ObjectBase [XmlInclude(typeof(MyObjectGroup))] // : ObjectBase public abstract class ObjectBase { /* */ } 

(l’approche exacte dépend du sérialiseur)

En règle générale, vous devez considérer les interfaces comme des contrats implémentés par certains types et les classes abstraites comme des nœuds dans la hiérarchie d’inheritance qui n’existent pas (c’est-à-dire qu’il existe une relation “est une” entre la classe dérivée et la classe abstraite de base). Cependant, dans la pratique, vous devrez peut-être utiliser des interfaces dans d’autres cas, comme lorsque vous avez besoin d’un inheritance multiple.

Par exemple, IXmlSerializable n’est pas une “entité” en soi. Il définit un contrat qu’une entité peut mettre en œuvre. Les interfaces vivent “en dehors” de la hiérarchie d’inheritance.

Une interface vous permettra de définir un «contrat» que l’object devra remplir en fournissant les propriétés et les méthodes décrites par l’interface. Vous pouvez faire référence à des objects par des variables de type interface, ce qui peut entraîner une certaine confusion quant à ce qui est proposé.

Une classe de base offre la possibilité de créer un “arbre” d’inheritance dans lequel des classes plus complexes (d’un “type” commun) sont construites sur les bases d’une classe “de base” plus simple. L’exemple classique et ennuyeux dans OO est normalement une classe de base de ‘Shape’ qui est héritée par Triangle, Square, etc.

Le point principal est qu’avec une interface, vous devez fournir l’intégralité du contrat à chaque classe qui l’implémente, avec un arbre d’inheritance (classes de base) que vous ne modifiez / ajoutez que les propriétés et méthodes propres à la classe enfant, propriétés communes et les méthodes restnt dans la classe de base.

Dans votre exemple ci-dessus, l’object “MyObjectGroup” hériterait de la classe de base “MyObject”. Vous ne pouvez donc rien tirer d’une interface ici.

Lors de la conception des cours, l’architecte a deux idées en tête.

  1. Comportement d’un object.
  2. mise en œuvre de l’object.

Si une entité a plusieurs implémentations, la séparation du comportement d’un object de son implémentation est l’une des clés de la maintenabilité et du découplage. La séparation peut être réalisée par classe abstraite ou par interface, mais laquelle est la meilleure? Prenons un exemple pour vérifier cela.

Prenons un scénario de développement où les éléments (demande, modèle de classe, etc.) changent très fréquemment et vous devez fournir certaines versions de l’application.

Énoncé initial du problème : vous devez créer une classe «Train» pour le chemin de fer indien, dont le comportement est maxSpeed ​​en 1970.

1. Business Modeling avec classe abstraite

V 0.0 (problème initial) Énoncé du problème initial: vous devez créer une classe de Train pour le chemin de fer indien dont le comportement est maxSpeed ​​en 1970.

 public abstract class Train { public int maxSpeed(); } 

V 1.0 (Problème 1 modifié ) Énoncé du problème modifié: Vous devez créer une classe de Diesel Train pour les chemins de fer indiens dont le comportement est maxSpeed, en 1975.

 public abstract class DieselTrain extends train { public int maxFuelCapacity (); } 

V 2.0 (problème modifié 2) énoncé du problème: vous devez créer une classe ElecsortingcalTrain pour le chemin de fer indien, dont le comportement est maxSpeed, maxVoltage en 1980.

 public abstract class ElecsortingcalTrain extends train { public int maxvoltage (); } 

V 3.0 (problème modifié 3)

Enoncé du problème: vous devez créer une HybridTrain (utilisant à la fois le diesel et l’élecsortingcité) pour les chemins de fer indiens, dont le comportement est maxSpeed, maxVoltage, maxVoltage en 1985.

 public abstract class HybridTrain extends ElecsortingcalTrain , DisealTrain { { Not possible in java } } {here Business modeling with abstract class fails} 

2. Business Modeling avec interface

Il suffit de changer le mot abstract pour l’ interface et …… votre modélisation d’entreprise avec interface réussira.

http://javaqna.wordpress.com/2008/08/24/why-the-use-on-interfaces-instead-of-abstract-classes-is-encouraged-in-java-programming/

Interface: Si vos classes enfants doivent toutes implémenter un certain groupe de méthodes / fonctionnalités mais que chacune des classes enfants est libre de fournir sa propre implémentation, utilisez des interfaces.

Par exemple, si vous implémentez une hiérarchie de classes pour véhicules, implémentez une interface appelée Véhicule qui possède des propriétés telles que Color MaxSpeed, etc., ainsi que des méthodes telles que Drive (). Toutes les classes enfants telles que Car Scooter AirPlane SolarCar, etc., doivent dériver de cette interface de base, mais fournissent une implémentation séparée des méthodes et propriétés exposées par Vehicle.

-> Si vous voulez que vos classes enfants implémentent plusieurs fonctionnalités non liées dans de multiples interfaces d’utilisation d’inheritance.

Par exemple, si vous implémentez une classe appelée SpaceShip qui doit avoir les fonctionnalités d’un véhicule ainsi que celle d’un OVNI, transformez véhicule et UFO en interface, puis créez une classe SpaceShip qui implémente à la fois véhicule et OVNI.

Classes abstraites:

-> Lorsque vous avez une exigence pour laquelle votre classe de base doit fournir l’implémentation par défaut de certaines méthodes alors que d’autres méthodes doivent pouvoir être remplacées par des classes enfants, utilisez des classes abstraites.

Par exemple, reprenons l’exemple de la classe de véhicules ci-dessus. Si nous voulons que toutes les classes dérivées de Vehicle implémentent la méthode Drive () de façon fixe, les autres méthodes peuvent être remplacées par des classes enfants. Dans un tel scénario, nous implémentons la classe Vehicle en tant que classe abstraite avec une implémentation de Drive tout en laissant les autres méthodes / propriétés en tant qu’abstraits afin qu’elles puissent être remplacées par des classes enfants.

-> Le but d’une classe abstraite est de fournir une définition commune d’une classe de base que plusieurs classes dérivées peuvent partager.

Par exemple, une bibliothèque de classes peut définir une classe abstraite utilisée comme paramètre pour bon nombre de ses fonctions et obliger les programmeurs utilisant cette bibliothèque à fournir leur propre implémentation de la classe en créant une classe dérivée.

Vous pouvez réellement aller avec les deux. ObjectBase vous évite de mettre en œuvre plusieurs fois les propriétés communes et implémente IObject pour vous. Partout où vous l’utilisez, référez-vous à IObject pour pouvoir tester plus tard des simulacres

Je préférerais les classes abstraites de base, parce que, théoriquement (bon, c’est une théorie, je ne prouve ni ne prétends qu’une autre est pire que celle-ci) – les interfaces doivent être utilisées, lorsque vous voulez montrer que object est capable de faire quelque chose (comme IComparable – vous montrez que tout ce qui l’implémente peut être comparé à autre chose), alors que lorsque vous avez 2 instances qui partagent juste quelque chose de commun ou ont 1 parent logique – des classes abstraites doivent être utilisées.
Vous pouvez également opter pour les deux approches, en utilisant la classe de base, qui implémentera une interface, qui indiquera explicitement ce que votre classe peut faire.

Toutes choses étant égales par ailleurs, allez avec l’interface. Plus facile à simuler pour les tests unitaires.

Mais en général, tout ce que j’utilise, c’est quand il y a un code commun que je préférerais mettre au même endroit, plutôt que chaque instance de la classe dérivée. Si c’est pour quelque chose comme ce que vous décrivez, où la façon dont ils sont utilisés est la même, mais dont les mécanismes sous-jacents sont différents, une interface semble plus appropriée.

J’ai utilisé des classes abstraites dans mes projets, mais dans les projets futurs, j’utiliserai des interfaces. L’avantage de “l’inheritance multiple” est extrêmement utile. Avoir la possibilité de fournir une implémentation complètement nouvelle de la classe, en code ou à des fins de test, est toujours le bienvenu. Enfin, si à l’avenir vous souhaitez pouvoir personnaliser votre code par des développeurs externes, vous n’avez pas à leur donner votre code réel, ils peuvent simplement utiliser les interfaces …

Si vous avez une fonction en classe, vous devriez utiliser la classe abstraite au lieu de l’interface. En général, une interface est utilisée pour être au nom d’un type.

Notez que vous ne pouvez pas remplacer les opérateurs dans les interfaces. C’est le seul problème qui me pose problème en ce qui me concerne.

Le choix d’interfaces et de classes abstraites n’est pas une proposition. Si vous devez modifier votre conception, faites-en une interface. Cependant, vous pouvez avoir des classes abstraites qui fournissent un comportement par défaut. Les classes abstraites sont d’excellents candidats dans les frameworks d’application.

Les classes abstraites vous permettent de définir certains comportements. ils forcent vos sous-classes à fournir aux autres. Par exemple, si vous avez un cadre d’application, une classe abstraite peut fournir des services par défaut tels que la gestion des événements et des messages. Ces services permettent à votre application de se connecter à votre infrastructure d’application. Cependant, il existe certaines fonctionnalités spécifiques à l’application que seule votre application peut exécuter. Cette fonctionnalité peut inclure des tâches de démarrage et d’arrêt, qui dépendent souvent de l’application. Ainsi, au lieu d’essayer de définir ce comportement lui-même, la classe de base abstraite peut déclarer des méthodes abstraites d’arrêt et de démarrage. La classe de base sait qu’elle a besoin de ces méthodes, mais une classe abstraite permet à votre classe d’admettre qu’elle ne sait pas comment effectuer ces actions. il sait seulement qu’il doit initier les actions. Au moment de démarrer, la classe abstraite peut appeler la méthode de démarrage. Lorsque la classe de base appelle cette méthode, Java appelle la méthode définie par la classe enfant.

De nombreux développeurs oublient qu’une classe qui définit une méthode abstraite peut également appeler cette méthode. Les classes abstraites sont un excellent moyen de créer des hiérarchies d’inheritance planifié. Ils constituent également un bon choix pour les classes sans feuilles dans les hiérarchies de classes.

La définition de la classe abstraite peut décrire le code et l’état, et les classes qui en dérivent ne peuvent pas provenir d’autres classes en même temps. C’est la différence technique.

Par conséquent, du sharepoint vue de l’utilisation et de la philosophie, la différence réside dans le fait qu’en configurant une classe abstraite, vous contraignez toute autre fonctionnalité que les objects de cette classe peuvent implémenter et vous fournissez à ces objects des fonctionnalités de base communes à tous les types de fichiers. tel object (qui est aussi une sorte de contrainte), tandis que, en configurant une interface, vous ne définissez aucune contrainte pour les autres fonctionnalités ni aucune disposition en code réel pour cette fonctionnalité que vous avez à l’esprit. Utilisez les classes abstraites lorsque vous savez tout ce que les objects de cette classe sont censés faire pour le bénéfice de leurs utilisateurs. Utilisez les interfaces lorsque les objects peuvent également faire autre chose que vous ne pouvez même pas deviner.