Cred ca una din cele mai frecvente intrebari din lumea .Net este legata de diferentele dintre o interfata si o clasa abstracta.
In acest articol mi-am propus sa raspund la aceasta intrebare si sa exemplific, prin cod, diferentele dintre cele doua notiuni.
Ce este o interfata ?
O interfata defineste un set de metode, proprietati, evenimente, indexatori. Acesti membri vor fi implementati de o clasa sau chiar de o structura.
Pentru mai multe informatii despre interfete puteti consulta articolul Interfete in .Net.
Ce este o clasa abstracta ?
O clasa abstracta este o clasa care nu poate fi instantiata si este folosita pentru mostenire.
O clasa care nu este abstracta si care deriveaza dintr-o clasa abstracta, trebuie sa includa implementarile tuturor membrilor abstracti.
Vom crea o interfata si o clasa abstracta, apoi le vom implementa/mosteni.
Scriem codul pentru o interfata.
/// <summary>
/// interface for Person
/// </summary>
public interface IPerson
{
#region properties for IPerson interface
string FirstName
{
get; set;
}
string LastName
{
get; set;
}
int Age
{
get; set;
}
#endregion
#region methods for IPerson interface
String Add();
String Delete();
int CalculateWage();
#endregion
}
Observatie 1:
Interfata contine doar signatura membrilor.
Observatie 2:
Daca nu se specifica nici un modificator de acces pentru interfata, atunci cel implicit va fi internal. Daca se afla in interiorul unei clase, o interfata poate avea modificatorii de access private, protected, public, internal.
Observatie 3:
O clasa poate implementa mai multe interfete.
Scriem codul pentru clasa abstracta:
/// <summary>
/// abstract class for Person
/// </summary>
public abstract class Person
{
#region fields for the abstrac class
protected string firstName;
protected string lastName;
protected int age;
#endregion
#region properties for the abstract class
public abstract string FirstName
{
get; set;
}
public abstract string LastName
{
get; set;
}
public abstract int Age
{
get; set;
}
#endregion
#region completed methods for the abstract class
string Add ()
{
return "New person " + firstName + " " + lastName + " added.";
}
string Delete ()
{
return "Person" + firstName + " " + lastName + " deleted.";
}
#endregion
#region abstract method
public abstract int CalculateWage();
#endregion
}
Observatie 1 :
Metoda CalculateWage este abstracta si poate fi implementata diferit in clasele derivate.
Observatie 2 :
Clasa abstracta poate avea ca membri si campuri (field).
Observatie 3 :
O clasa poate mosteni o singura clasa abstracta.
Observatie 4 :
O clasa poate furniza atat membri abstracti cat si membri cu implementare concreta.
Cream clasa Employee care va implementa interfata IPerson:
/// <summary> /// class Employee implements IPerson interface /// </summary> class Employee : IPerson { //must define the filds //and implement the properties protected string firstName; protected string lastName; protected int age; public string FirstName { get { return firstName; } set { firstName = value; } } public string LastName { get { return lastName; } set { lastName = value; } } public int Age { get { return age; } set { age = value; } } //implement methods public string Add() { return "New Person " + firstName + " " + lastName + " added"; } public string Delete() { return "Person " + firstName + " " + lastName + " deleted"; } public int CalculateWage() { return 100; } }
Observatie :
Daca adaugam un nou membru la o interfata, atunci va trebui sa urmarim toate implementarile interfetei si sa scriem cod pentru implementarea noului membru.
Cream clasa Student care va mosteni clasa abstracta Person.
class Student : Person
{
#region Overrides of Person
public override string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public override string LastName
{
get { return lastName; }
set { lastName = value; }
}
public override int Age
{
get { return age; }
set { age = value; }
}
public override int CalculateWage()
{
return 0;
}
#endregion
}
Observatie :
Daca adaugam un nou membru la o clasa abstracta ii putem adauga o implementare implicita si nu vom avea probleme cu codul existent.
Cream instante pentru clasele Student si Employee si le testam.
Student s = new Student();
s.FirstName = "marius";
s.LastName = "istudor";
s.Age = 24;
Console.WriteLine(s.Add());
Console.WriteLine(s.Delete());
Console.WriteLine("Wage: {0}",s.CalculateWage());
Employee e = new Employee();
e.FirstName = "adrian";
e.LastName = "zelter";
e.Age = 34;
Console.WriteLine(e.Add());
Console.WriteLine(e.Delete());
Console.WriteLine("Wage: {0}",e.CalculateWage());
Daca o clasa abstracta implementeaza o interfata, atunci vor trebui implementati toti membri interfetei.
Declaram o metoda virtual pentru a o putea suprascrie in clasa derivata.
/// <summary> /// abstract class implements IPerson interface /// </summary> public abstract class Child : IPerson { #region Implementation of IPerson public string FirstName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string LastName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public int Age { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string Add() { throw new NotImplementedException(); } public string Delete() { throw new NotImplementedException(); } public virtual int CalculateWage() { throw new NotImplementedException(); } #endregion }
Putem mosteni clasa abstracta Child fara a intampina probleme. De asemenea, putem suprascrie metoda CalculateWage.
public class Boy : Child
{
public override int CalculateWage()
{
return 1;
}
}
Concluzii:
O interfata nu contine cod pentru implementare, ea contine doar signaturile.
O clasa abstracta poate contine codul complet sau partial, care poate fi rescris.
O interfata nu poate contine ca membri: constante, constructori, destructori, campuri, membri statici sau alte interfete.
Intr-o clasa abstracta se pot defini campuri, constante, metode, proprietati.
Din punct de vedere al vitezei de executie, o interfata este mai lenta decat o clasa abstracta.
mehigh says:
Și atunci de ce/cînd interfață?
zeltera says:
Raspunsul la intrebarea ta nu e simplu, si uneori tine si de stilul tau de programare.
Eu lucrez cu interfete in momentul in care vreau sa fiu sigur ca anumite clase implementeaza o metoda (de exemplu, IParser – cu metoda Parse – pentru a defini un arbore de clase care pot primi un parametru de un tip pe care sa il transforme, parse, in alt tip). O clasa abstract o folosesc in momentul in care am nevoie de un set de clase de baza (una sau mai multe) pe care sa imi construiesc clasele necesare aplicatiei. Un exemplu clasic e Person, care e abstracta, si din care poti creea clasele Student, Employee, Teacher etc.
Mai pe scurt spus, daca scopul e sa impui o “interfata”, adica un set de metode, folosesc Interface. Daca scopul este sa dezvolt o baza pe care sa construiesc clase specializate folosesc o clasa abstracta.
mehigh says:
Tocmai citesc într-un chestionar și un alt răspuns: „It makes the code more generic”. :)
marius says:
@Mehigh
Cred ca depinde de scenarii si de ce anume ai nevoie.
Daca preferi interfetele, recomandarea este sa nu abuzezi in folosirea lor.
mehigh says:
Ok. Îmi plac articolele tale. Să nu te oprești.