J'ai une classe avec des fonctionnalités par défaut / partagées. J'utilise abstract class
pour cela:
public interface ITypeNameMapper
{
string Map(TypeDefinition typeDefinition);
}
public abstract class TypeNameMapper : ITypeNameMapper
{
public virtual string Map(TypeDefinition typeDefinition)
{
if (typeDefinition is ClassDefinition classDefinition)
{
return Map(classDefinition);
}
...
throw new ArgumentOutOfRangeException(nameof(typeDefinition));
}
protected abstract string Map(ClassDefinition classDefinition);
}
Comme vous pouvez le voir, j'ai également l'interface ITypeNameMapper
. Est-il judicieux de définir cette interface si j'ai déjà une classe abstraite TypeNameMapper
ou si abstract class
c'est juste assez?
TypeDefinition
dans cet exemple minimal est également abstrait.
c#
interfaces
abstract-class
Konrad
la source
la source
Réponses:
Oui, car C # n'autorise pas l'héritage multiple sauf avec les interfaces.
Donc, si j'ai une classe qui est à la fois TypeNameMapper et SomethingelseMapper, je peux faire:
la source
ICanFly
,ICanRun
,ICanSwim
. Vous devez créer 8 classes de créatures, une pour chaque combinaison de traits (YYY, YYN, YNY, ..., NNY, NNN). SRP indique que vous implémentez chaque comportement (voler, courir, nager) une fois puis les implémenter de manière réutilisable sur les 8 créatures. La composition serait encore meilleure ici, mais en ignorant la composition pendant une seconde, vous devriez déjà voir la nécessité d'hériter / implémenter plusieurs comportements réutilisables séparés en raison de SRP.interface
faute professionnelle craptaculaire .. des implémentations redondantes qui devraient être dans la base - qui évoluent indépendamment !, des changements de logique conditionnelle conduisant cette ordure faute de méthodes de modèle, d'encapsulation cassée, d'abstraction inexistante. Mon préféré: les classes à 1 méthode implémentant chacune sa propre méthode à 1interface
, chacune avec une seule instance. ... etc, etc, et etc.Les interfaces et les classes abstraites ont différentes fonctions:
Dans votre exemple,
interface ITypeNameMapper
définit les besoins des clients etabstract class TypeNameMapper
n'ajoute aucune valeur.la source
public
appartient au client.TypeNameMapper
ajoute beaucoup de valeur car il évite à l'implémenteur d'écrire une logique commune.interface
non ou non n'est pertinent que dans la mesure où C # interdit l'héritage multiple complet.L'ensemble du concept d'interfaces a été créé afin de supporter une famille de classes ayant une API partagée.
Cela signifie explicitement que toute utilisation d'une interface implique qu'il y a (ou devrait avoir) plus d'une implémentation de sa spécification.
Les cadres DI ont brouillé les eaux ici dans la mesure où beaucoup d'entre eux nécessitent une interface même s'il n'y aura qu'une seule implémentation - pour moi, cela représente un surcoût déraisonnable pour ce qui, dans la plupart des cas, n'est qu'un moyen plus complexe et plus lent d'appeler le nouveau, mais il c'est ce que c'est.
La réponse réside dans la question elle-même. Si vous avez une classe abstraite, vous vous préparez à la création de plusieurs classes dérivées avec une API commune. Ainsi, l'utilisation d'une interface est clairement indiquée.
la source
find ... -exec perl -pi -e ...
et éventuellement corriger des erreurs de compilation triviales. Mon point est: L'avantage de ne pas avoir une chose (actuellement) inutile est beaucoup plus grand que les économies futures possibles.interface
tant que code (vous parlez de C # -interface
s, pas une interface abstraite, comme tout ensemble de classes / fonctions / etc), et la terminiez "... mais toujours hors la loi du multiple complet héritage." Il n'y a pas besoin deinterface
s si vous avez un IM.Si nous voulons répondre explicitement à la question, l'auteur dit "Est-il judicieux de définir cette interface si j'ai déjà une classe abstraite TypeNameMapper ou une classe abstraite est juste suffisante?"
La réponse est oui et non - Oui, vous devez créer l'interface même si vous avez déjà la classe de base abstraite (car vous ne devez pas faire référence à la classe de base abstraite dans aucun code client), et non, car vous ne devriez pas avoir créé la classe de base abstraite en l'absence d'une interface.
Le fait que vous n'ayez pas suffisamment réfléchi à l'API que vous essayez de créer est évident. Proposez d'abord l'API, puis fournissez une implémentation partielle si vous le souhaitez. Le fait que votre classe de base abstraite vérifie le code dans le code suffit pour vous dire que ce n'est pas la bonne abstraction.
Comme dans la plupart des choses dans OOD, lorsque vous êtes dans le groove et que votre modèle d'objet est bien fait, votre code vous informera de ce qui va suivre. Commencez avec une interface, implémentez cette interface dans les classes dont vous avez besoin. Si vous vous retrouvez en train d'écrire du code similaire, extrayez-le dans une classe de base abstraite - c'est l'interface qui est importante, la classe de base abstraite n'est qu'une aide et il peut y en avoir plus d'une.
la source
Il est assez difficile de répondre sans connaître le reste de l'application.
En supposant que vous utilisez une sorte de modèle DI et que vous avez conçu votre code pour qu'il soit aussi extensible que possible (afin que vous puissiez en ajouter
TypeNameMapper
facilement), je dirais oui.Raisons pour:
interface
vous n'avez pas besoin de vous en soucier dans les implémentations enfantsinterface
s. Bien que beaucoup d'entre eux fonctionnent avec des classes abstraites, ce n'est pas toujours une donnée et je suis très partisan de suivre le même chemin que les autres 99% des utilisateurs d'une bibliothèque lorsque cela est possible.Raisons contre:
class
/interface
change, il y a un petit surcoût supplémentaireTout bien considéré, je dirais que vous devez créer le
interface
. Les raisons contre sont assez négligeables mais, bien qu'il soit possible d'utiliser des résumés dans la simulation et l'IoC, c'est souvent beaucoup plus facile avec les interfaces. En fin de compte, je ne critiquerais pas le code d'un collègue s'il allait dans l'autre sens.la source