Wanneer gebruik je een abstracte klasse versus interface in C #

Bij het ontwerpen van applicaties is het belangrijk om te weten wanneer je een abstracte klasse moet gebruiken en wanneer je een interface moet gebruiken. Hoewel abstracte klassen en interfaces in sommige opzichten op elkaar lijken, zijn er belangrijke verschillen die bepalen wat de beste keuze is voor wat u probeert te bereiken. In deze blogpost bespreek ik die verschillen en hoe je kunt beslissen wanneer je welke wilt gebruiken.

Het korte antwoord: met een abstracte klasse kunt u functionaliteit creëren die subklassen kunnen implementeren of overschrijven. Met een interface kunt u alleen functionaliteit definiëren, niet implementeren. En hoewel een klasse slechts één abstracte klasse kan uitbreiden, kan deze profiteren van meerdere interfaces. 

C # abstracte klasse uitgelegd

Een abstracte klasse is een speciaal type klasse dat niet kan worden geïnstantieerd. Een abstracte klasse is ontworpen om te worden overgeërfd door subklassen die de methoden ervan implementeren of overschrijven. Met andere woorden, abstracte klassen zijn gedeeltelijk geïmplementeerd of helemaal niet geïmplementeerd. U kunt functionaliteit in uw abstracte klasse hebben - de methoden in een abstracte klasse kunnen zowel abstract als concreet zijn. Een abstracte klasse kan constructors hebben - dit is een belangrijk verschil tussen een abstracte klasse en een interface. U kunt profiteren van abstracte klassen om componenten te ontwerpen en een bepaald niveau van algemene functionaliteit te specificeren dat moet worden geïmplementeerd door afgeleide klassen.

C # interface uitgelegd

Een interface is in feite een contract - het heeft geen enkele implementatie. Een interface kan alleen methodedeclaraties bevatten; het kan geen methodedefinities bevatten. Evenmin kunt u gegevens van leden in een interface hebben. Terwijl een abstracte klasse methodedefinities, velden en constructors kan bevatten, kan een interface alleen declaraties hebben van events, methoden en eigenschappen. Methoden die in een interface worden gedeclareerd, moeten worden geïmplementeerd door de klassen die de interface implementeren. Merk op dat een klasse meer dan één interface kan implementeren, maar slechts één klasse kan uitbreiden. De klasse die de interface implementeert, moet al zijn leden implementeren. Net als een abstracte klasse kan een interface niet worden geïnstantieerd.

Moet ik een abstracte klasse of een interface gebruiken?

Abstracte klassen bieden u de flexibiliteit om bepaalde concrete methoden te hebben en enkele andere methoden die de afgeleide klassen zouden moeten implementeren. Als u daarentegen interfaces gebruikt, moet u alle methoden in de klasse implementeren die de interface uitbreiden. Een abstracte klasse is een goede keuze als u plannen heeft voor toekomstige uitbreiding, dwz als een toekomstige uitbreiding waarschijnlijk is in de klassenhiërarchie. Als u ondersteuning wilt bieden voor toekomstige uitbreidingen bij het gebruik van interfaces, moet u de interface uitbreiden en een nieuwe maken.

Anders gezegd: het is gemakkelijk om indien nodig een nieuwe interface aan de hiërarchie toe te voegen. Als u echter al een abstracte klasse in uw hiërarchie heeft, kunt u geen andere toevoegen, dwz u kunt alleen een abstracte klasse toevoegen als er geen beschikbaar is. U moet een interface gebruiken als u een contract wilt voor een bepaald gedrag of functionaliteit. U moet geen interface gebruiken als u dezelfde code moet schrijven voor de interfacemethoden. In dit geval moet u een abstracte klasse gebruiken, de methode één keer definiëren en deze indien nodig opnieuw gebruiken. Gebruik interfaces om de code van uw applicatie los te koppelen van specifieke implementaties ervan, of om de toegang te beperken tot leden van een bepaald type.

Zoals in de documentatie van interfaces van Microsoft staat:

Door interfaces te gebruiken, kun je bijvoorbeeld gedrag uit meerdere bronnen in een klas opnemen. Die mogelijkheid is belangrijk in C # omdat de taal geen ondersteuning biedt voor meerdere overerving van klassen. Bovendien moet u een interface gebruiken als u overerving voor structs wilt simuleren, omdat ze niet echt kunnen erven van een andere struct of klasse.

Impliciete en expliciete interface-implementaties

Interfaces kunnen impliciet of expliciet worden geïmplementeerd. Laat me uitleggen hoe deze twee implementaties verschillen. Overweeg een interface genaamd IBusinessLogic.

openbare interface IBusinessLogic

{

   void Initialize ();

}

De volgende klasse met de naam BusinessLogicimplementeert de IBusinessLogicinterface.

openbare klasse BusinessLogic: IBusinessLogic

{

   public void Initialize ()

   {

       // Sommige code

   }

}

U kunt BusinessLogicexpliciet een instantie van de klasse maken en vervolgens de Initialize()methode aanroepen zoals hieronder wordt weergegeven.

 IBusinessLogic businessLogic = nieuwe BusinessLogic ();

businessLogic.Initialize ();

Het volgende codefragment illustreert hoe u de IBusinessLogicinterface impliciet kunt implementeren .

openbare klasse BusinessLogic: IBusinessLogic

{

   void IBusinessLogic.Initialize ()

   {

   }

}

U kunt de Initialize()methode nu op dezelfde manier aanroepen met een verwijzing naar de IBusinessLogicinterface. Het verschil tussen de twee benaderingen is dat wanneer u de interface expliciet in uw klas implementeert, u beperkt bent tot het aanroepen van een methode van uw interface met alleen een verwijzing naar de interface. Daarom zou het volgende codefragment niet werken, dwz niet compileren.

 BusinessLogic businessLogic = nieuwe BusinessLogic ();

businessLogic.Initialize ();

Hoe u meer kunt doen in C #:

  • Wanneer gebruik je een abstracte klasse versus interface in C #
  • Werken met AutoMapper in C #
  • Lambda-uitdrukkingen gebruiken in C #
  • Werken met afgevaardigden van Action, Func en Predicate in C #
  • Werken met afgevaardigden in C #
  • Hoe een eenvoudige logger in C # te implementeren
  • Werken met attributen in C #
  • Hoe te werken met log4net in C #
  • Hoe het repository-ontwerppatroon in C # te implementeren
  • Werken met reflectie in C #
  • Hoe te werken met filesystemwatcher in C #
  • Hoe luie initialisatie uit te voeren in C #
  • Werken met MSMQ in C #
  • Werken met uitbreidingsmethoden in C #
  • Hoe lambda-uitdrukkingen in C # te gebruiken
  • Wanneer gebruik je het vluchtige trefwoord in C #
  • Het zoekwoord rendement gebruiken in C #
  • Hoe polymorfisme in C # te implementeren
  • Hoe u uw eigen taakplanner kunt bouwen in C #
  • Hoe te werken met RabbitMQ in C #
  • Werken met een tupel in C #
  • Virtuele en abstracte methoden verkennen in C #