Prosto i rzeczowo 🙂
Interface jest definicją(wzorem) dla klas, które będą go implementować.
W interfejsie określa się np. jakie metody mają być zdefiniowane w klasie. Klasa, która będzie dziedziczyć po interfejsie musi posiadać metody zdefiniowane w interfejsie.
Szybki przykład pokazujący o co chodzi w praktyce
public interface IBook
{
public int GetPageCount();
public string GetPrice();
}
public class Book : IBook
{
public int GetPageCount()
{
return 300;
}
public string GetPrice()
{
return "30 złoty";
}
}
Mamy interfejs IBook oraz klasę, która dziedziczy po interfejsie i musi posiadać metody, które zostały zdefiniowane w interfejsie zgodnie z wzorem.
Ważne
- Interfejs w C# tworzymy używając słowa Interface
- Dobrą praktyką jest pisać “I” na początku interfejsu, żeby w kodzie lepiej widoczne było, że jest to interface
- Dziedziczenie po interface jest podobne jak w przypadku dziedziczenia po klasach i używamy “:” żeby podziedziczyć.
- Super ważne: klasa może dziedziczyć tylko po jednej klasie (więcej tutaj), ale może dziedziczyć po wielu interfejsach
- Do C# 8.0 metody w interfejsach nie mogą być implementowane, tzn. są tylko definicjami i nie mogą posiadać ciał. (są jak wzór pisma w urzędzie, który jest zalaminowany i wisi na ścianie ). Od C# 8.0 (wersja od sierpnia 2019) metody w interfejsach mogą być implementowane w prosty sposób. Są trochę jak wniosek, który można pobrać, i który ma już wypełnione np. dane kontaktowe i wymaga tylko podpisu (zostając w przykładach urzędowych :p )
Przykład interfejsu od wersji C# 8.0
public interface IFantasyBook
{
public int GetPageCount();
public string GetPrice();
public string GetBookType()
{
return "Fantasy Book";
}
}
public class HarryPotterSeriesBook : IFantasyBook
{
public int GetPageCount()
{
return 300;
}
public string GetPrice()
{
return "30 złoty";
}
}
public class TheLordOfTheRingsSerisesBook : IFantasyBook
{
public int GetPageCount()
{
return 240;
}
public string GetPrice()
{
return "50 złoty";
}
}
A tutaj przykład jak zrobić to samo przed wersją C# 8.0
public interface IFantasyBook
{
public int GetPageCount();
public string GetPrice();
public string GetBookType();
}
public class HarryPotterSeriesBook : IFantasyBook
{
public int GetPageCount()
{
return 300;
}
public string GetPrice()
{
return "30 złoty";
}
public string GetBookType()
{
return "Fantasy Book";
}
}
public class TheLordOfTheRingsSerisesBook : IFantasyBook
{
public int GetPageCount()
{
return 240;
}
public string GetPrice()
{
return "50 złoty";
}
public string GetBookType()
{
return "Fantasy Book";
}
}
Jak widać tutaj musieliśmy powtórzyć kod i w obu klasach zaimplementować metodę GetBookType tak samo, aby to obejść i nie powtarzać kodu trzeba wprowadzić jakąś klasę, po której będą dziedziczyć obie klasy.
public interface IFantasyBook
{
public int GetPageCount();
public string GetPrice();
public string GetBookType();
}
public abstract class FantasyBook : IFantasyBook
{
public abstract int GetPageCount();
public abstract string GetPrice();
public string GetBookType()
{
return "Fantasy Book";
}
}
public class HarryPotterSeriesBook : FantasyBook, IFantasyBook
{
public override int GetPageCount()
{
return 300;
}
public override string GetPrice()
{
return "30 złoty";
}
}
public class TheLordOfTheRingsSerisesBook : FantasyBook, IFantasyBook
{
public override int GetPageCount()
{
return 240;
}
public override string GetPrice()
{
return "50 złoty";
}
}
Tutaj też trzeba dopisać trochę dodatkowego kodu, żeby nie powtarzać ciała metody GetBookType.
Jak widać implementowane interfejsy jest to ułatwienie w pewnych przypadkach, więc warto o tym pamiętać, że można implementować już interfejsy, ale nie trzeba. Jeżeli jest to coś z czym się źle czujesz, możesz dalej stosować interfejsy tylko jako wzory dla klas 🙂
Na koniec jeszcze ostatnia rada 🙂 Stosuj interfejsy! Mają one jedną mega ważna zaletę klasy, mogą dziedziczyć po więcej niż jednym interfejsie i dzięki interfejsom wymuszasz jak mają wyglądać klasy. To naprawdę bardzo przydatne w programowaniu.
Warto zrozumieć ten temat, bo to naprawdę ważne zagadnienie.