Je suis conscient que c'est une question très basique, mais un intervieweur m'a posé une question très astucieuse et j'étais impuissant :(
Je ne connais que la définition matérielle ou théorique d'une interface et l'ai également implémentée dans de nombreux projets sur lesquels j'ai travaillé. Mais je ne comprends vraiment pas pourquoi et comment cela est-il utile.
Je ne comprends pas non plus une chose dans l'interface. c'est-à-dire que nous utilisons
conn.Dispose();
in finally block. Mais je ne vois pas que la classe implémente ou hérite de la classe IDisposable
interface (SqlConnection
) que je veux dire. Je me demande comment je peux simplement appeler le nom de la méthode. Dans le même ordre d'idées, je ne comprends pas comment fonctionne la méthode Dispose car nous devons implémenter le corps de la fonction avec notre propre implémentation pour toutes les méthodes d'interface. Alors, comment les interfaces sont acceptées ou nommées en tant que contrats? Ces questions ont continué à me trotter dans la tête jusqu'à présent et, franchement, je n'ai jamais vu de fil conducteur qui expliquerait mes questions de manière compréhensible.
MSDN, comme d’habitude, a l’air très effrayant et aucune ligne n’est claire ( Les gens, veuillez excuser les développeurs de haut niveau, j’ai le sentiment que tout code ou article devrait atteindre l’esprit de ceux qui le voient, par conséquent, comme beaucoup d’autres , MSDN n'est pas utile ).
L'intervieweur a déclaré:
Il a 5 méthodes et il est heureux de l'implémenter directement dans la classe, mais si vous devez choisir une classe ou une interface abstraite, laquelle choisissez-vous et pourquoi? Je lui ai répondu à toutes les informations que j'ai lues dans divers blogs en disant qu'il est avantageux et désavantageux pour la classe abstraite et l'interface, mais il n'est pas convaincu, il essaie de comprendre "Pourquoi interface" en général. "Pourquoi classe abstraite" en général, même si je ne peux implémenter les mêmes méthodes qu'une seule fois et ne pas le changer.
Je ne vois nulle part dans le réseau, je pourrais obtenir un article qui m'expliquerait clairement sur les interfaces et son fonctionnement. Je suis l’un de ces nombreux programmeurs qui ne connaissent toujours pas les interfaces (je connais la théorie et les méthodes que j’ai utilisées), mais je ne suis pas convaincu de l’avoir bien compris.
Les interfaces sont excellentes lorsque vous voulez créer quelque chose comme ça:
using System;
namespace MyInterfaceExample
{
public interface IMyLogInterface
{
//I want to have a especific method that I'll use in MyLogClass
void WriteLog();
}
public class MyClass:IMyLogInterface
{
public void WriteLog()
{
Console.Write("MyClass was Logged");
}
}
public class MyOtherClass :IMyLogInterface
{
public void WriteLog()
{
Console.Write("MyOtherClass was Logged");
Console.Write("And I Logged it different, than MyClass");
}
}
public class MyLogClass
{
//I created a WriteLog method where I can pass as parameter any object that implement IMyLogInterface.
public static void WriteLog(IMyLogInterface myLogObject)
{
myLogObject.WriteLog(); //So I can use WriteLog here.
}
}
public class MyMainClass
{
public void DoSomething()
{
MyClass aClass = new MyClass();
MyOtherClass otherClass = new MyOtherClass();
MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
}
}
}
Dans mon exemple, je pourrais être un développeur qui écrit MyLogClass
et les autres développeurs pourraient créer leurs classes et, lorsqu'ils voudraient se connecter, ils implémentent l'interface IMyLogInterface
. C'est comme ils me demandaient ce qu'ils devaient implémenter pour utiliser la méthode WriteLog()
dans MyLogClass
. La réponse qu'ils trouveront dans l'interface.
Les interfaces sont des contrats que les développeurs doivent respecter. Les classes abstraites autorisent les contrats ainsi que les implémentations partagées - ce que les interfaces ne peuvent pas avoir. Les classes peuvent implémenter et hériter de plusieurs interfaces. Les classes ne peuvent étendre qu'une seule classe abstraite.
IDbCommand
a SqlCommand
et OracleCommand
qui implémentent l'interface de manière spécifique}J'utilise des interfaces, notamment parce que cela augmente la flexibilité du code. Supposons que nous ayons une méthode qui prend un objet de type de classe Account en paramètre, tel que:
public void DoSomething(Account account) {
// Do awesome stuff here.
}
Le problème avec ceci est que le paramètre de méthode est fixé pour une implémentation d'un compte. C'est bien si vous n'avez jamais besoin d'un autre type de compte. Prenons cet exemple, qui utilise plutôt une interface de compte en tant que paramètre.
public void DoSomething(IAccount account) {
// Do awesome stuff here.
}
Cette solution n'est pas fixée vers une implémentation, ce qui signifie que je peux lui passer un compte SuperSavingsAccount ou ExclusiveAccount (implémentant l'interface IAccount) et obtenir un comportement différent pour chaque compte implémenté.
En un mot - à cause de polymorphisme !
Si vous "Programmez sur une interface, pas une implémentation", vous pouvez injecter différents objets partageant la même interface (type) dans la méthode en tant qu'argument. De cette manière, votre code de méthode n'est associé à aucune implémentation d'une autre classe, ce qui signifie qu'il est toujours ouvert pour travailler avec des objets nouvellement créés de la même interface. (Principe d'ouverture/fermeture)
Donc, dans cet exemple, le PowerSocket ne sait rien d’autre sur les autres objets. Les objets dépendent tous de la puissance fournie par le PowerSocket. Ils implémentent donc IPowerPlug et peuvent ainsi s'y connecter.
Les interfaces sont utiles car elles fournissent des contrats que les objets peuvent utiliser pour travailler ensemble sans avoir besoin de savoir quoi que ce soit les uns des autres.
C # n'a pas de dactylographie - ce n'est pas parce que vous savez qu'une méthode est implémentée dans un ensemble de classes concrètes que vous pouvez les traiter de la même manière en ce qui concerne l'appel de cette méthode. L'implémentation d'une interface vous permet de traiter toutes les classes l'implémentant comme le même type d'objet, en ce qui concerne ce que cette interface définit.
La classe abstraite et l'interface sont des contrats.
L'idée d'un contrat est que vous spécifiez un comportement. Si vous dites que vous avez mis en œuvre, vous avez accepté le contrat.
Le choix de l’abrégé sur l’interface est.
Tout descendant non abstrait de la classe abstraite implémentera le contrat.
contre
Toute classe qui implémente l'interface implémentera le contrat.
Vous utilisez donc abstract lorsque vous souhaitez spécifier un comportement que tous les descendants doivent implémenter et vous-même, définissez une interface distincte, mais maintenant, tout ce qui correspond à ce contrat agrégé doit être un descendant.
Vous ne pouvez hériter que d'une classe abstraite. Vous pouvez hériter de plusieurs interfaces. Cela détermine ce que j'utilise dans la plupart des cas.
L'avantage de la classe abstraite serait que vous pouvez avoir une implémentation de base. Cependant, dans le cas de IDisposable, une implémentation par défaut est inutile, car la classe de base ne sait pas comment nettoyer correctement les choses. Ainsi, une interface serait plus appropriée.
Avec une interface, vous pouvez effectuer les opérations suivantes:
1) Créez des interfaces séparées offrant des réductions différentes de votre implémentation, permettant une interface plus cohérente.
2) Autorisez plusieurs méthodes portant le même nom entre les interfaces, car vous n'avez pas d'implémentation en conflit, mais une signature.
3) Vous pouvez mettre à jour et personnaliser votre interface indépendamment de votre implémentation, afin de garantir le respect du contrat.
4) Votre code peut s’appuyer sur l’abstraction plutôt que sur la concrétion, ce qui permet une injection de dépendance intelligente, y compris l’injection de tests Mocks, etc.
Il y a bien d'autres raisons, j'en suis sûr, quelques unes seulement.
Une classe abstraite vous permet de travailler depuis une base partiellement concrète. Ce n’est pas la même chose qu’une interface, mais elle possède ses propres qualités, telles que la possibilité de créer une implémentation partielle à l’aide du modèle de méthode template.
Je pense que beaucoup de sang a déjà coulé en posant cette question, et beaucoup essaient de résoudre ce problème en expliquant des termes semblables à des robots qu'aucun humain normal ne peut comprendre.
Alors d'abord. pour savoir pourquoi l’interface et l’abstrait, vous devez savoir à quoi ils servent. J'ai personnellement appris cela lors de l'application de Factory Class. vous trouvez un bon tutoriel sur ce lien
Maintenant, dig-in base sur le lien que j'ai déjà donné.
Vous avez la classe Vehicle qui peut changer selon les besoins de l'utilisateur (comme ajouter camion, réservoir, avion, etc.
public class clsBike:IChoice
{
#region IChoice Members
public string Buy()
{
return ("You choose Bike");
}
#endregion
}
et
public class clsCar:IChoice
{
#region IChoice Members
public string Buy()
{
return ("You choose Car");
}
#endregion
}
et les deux ont contrat IChoice qui dit simplement que ma classe devrait avoir la méthode d'achat
public interface IChoice
{
string Buy();
}
Vous voyez maintenant que cette interface applique uniquement la méthode Buy()
, mais laisse la classe héritée décider quoi faire lorsqu'elle l'implémente. C’est la limitation d’Interface. En utilisant uniquement l’interface, vous pourriez finir par répéter une tâche que nous pouvons implémenter automatiquement en utilisant abstact. Sur notre exemple, disons, l'achat de chaque véhicule a un rabais.
public abstract class Choice
{
public abstract string Discount { get; }
public abstract string Type { get; }
public string Buy()
{
return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
public abstract string Discount { get { return "10% Discount Off"; } }
public abstract string Type { get { return "Bike"; } }
}
public class clsCar:Choice
{
public abstract string Discount { get { return " $15K Less"; } }
public abstract string Type { get { return "Car"; } }
}
Maintenant, en utilisant Factory Class, vous pouvez obtenir le même résultat, mais en utilisant abstract, vous laissez la classe de base exécuter la méthode Buy()
.
Dans Résumé: les contrats Interface permettent à la classe héritée d'effectuer l'implémentation while Abstract class Les contrats peuvent initialiser l'implémentation (ce qui peut remplacer la classe Inherit)
Les interfaces permettent au concepteur de classes de rendre les méthodes disponibles très claires pour l'utilisateur final. Ils font également partie intégrante du polymorphisme.
Je ne publierai pas la définition d'une interface par rapport à une classe abstraite car je pense que vous connaissez très bien la théorie et je suppose que vous connaissez les principes SOLID, alors allons-y de manière pratique.
Comme vous le savez, les interfaces ne peuvent pas contenir de code, de sorte que l’inverse est assez simple à comprendre.
si vous devez initialiser la propriété de votre classe en fournissant un constructeur ou si vous souhaitez fournir une partie de l'implémentation, une classe abstraite conviendrait bien à une interface qui ne vous permettrait pas de le faire.
En général, vous devriez donc préférer les classes abstraites aux interfaces lorsque vous devez fournir au constructeur un code ou un code qui héritera/étendra votre classe.
En tant que véritable échantillon de @ user2211290, répondez:
'Array' et 'List' ont tous deux l'interface IList
. Nous créons un exemple avec une chaîne [] et une liste et faisons des tests courants en utilisant IList :
string[] col1 = { "zero", "one", "two", "three", "four"};
List<string> col2 = new List<string>{ "zero", "one", "two", "three"};
static void CheckForDigit(IList collection, string digit)
{
Console.Write(collection.Contains(digit));
Console.Write(" ");
Console.WriteLine(collection.ToString());
}
static void Main()
{
CheckForDigit(col1, "one"); //True System.String[]
CheckForDigit(col2, "one"); //True System.Collections.Generic.List`1[System.String]
//Another test:
CheckForDigit(col1, "four"); //True System.String[]
CheckForDigit(col2, "four"); //false System.Collections.Generic.List`1[System.String]
}