Witaj. Chciałbym dzisiaj trochę rozjaśnić Ci sprawę związaną z interfejsami. Zacznijmy od tego, że jest to nieodzowny element, który powinien znać każdy dobry programista, zatem jeżeli jeszcze wcześniej o nich nie słyszałeś to dobrze, że tutaj trafiłeś. Przede wszystkim musisz zrozumieć po co implementuje się interfejsy, oraz jakie niesie to za sobą skutki. Ale za nim do tego dojdziemy pokażę Ci w jaki sposób stworzyć interfejs w Twoim projekcie. Najprościej będzie Ci zrozumieć to na jakimś sensownym przykładzie, dlatego w tym celu stworzymy prostą aplikację konsolową, w której człowiek będzie miał umiejętności (żeby nie tworzyć dużego projektu, będzie to tylko tancerz oraz muzyk). Standardowo tworzymy projekt konsolowy, a w nim tworzymy trzy nowe klasy. Person(osoba, człowiek), Musican(muzyk), Dancer(tancerz). Klasy Musican i Dancer będą dziedziczyć po klasie Person.
Klasa Person będzie zawierała w sobie wszystkie cechy wspólne wszystkich klas, tzn. wzrost, waga, wiek, itd. Natomiast pozostałe dwie klasy będą zawierały cechy związane z umiejętnością, tzn. np. gra na skrzypcach, taniec klasyczny.
Całość gotowa do rozpoczęcia omawiania interfejsów wyglądałaby następująco:
Klasa Person.cs
Klasa Musican.cs
Klasa Dancer.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { public class Dancer : Person { // zatańcz taniec breakdance public void DanceBreakdance() { Console.WriteLine("Tanczę Breakdance."); } // zatancz taniec klasyczny public void DanceClassic() { Console.WriteLine("Tanczę taniec klasyczny."); } } } |
Mając takie klasy możemy przejść do tworzenia interfejsów. Zanim jednak go utworzymy pojawia się pierwsza cenna wskazówka. Nazwy interfejsów zaczynamy dużą literą “I” (od słowa interface, jest to praktyka programistów). Pierwszym jaki utworzymy będzie interfejs dla tancerza zatem plik nazywać się będzie IDancer.cs. W tym celu klikamy prawym przyciskiem myszy na nasz projekt w Solution Explorerze, a następnie klikamy “Add” i “Class”. Potem zamiast “Class” wybieramy “Interface” i zatwierdzamy, a Visual Studio wygenerowało dla nas pusty Interface.
Powinieneś otrzymać taki plik:
Interfejs IDancer.cs
Okej w końcu stworzyliśmy nasz interface. Teraz wypada sobie troche o nich powiedzieć i zaznaczyć najważniejsze aspekty.
Interfejs mówi klasie, że musi ona zaimplementować określone metody oraz właściwości. Jeżeli klasa nie posiada takowych, kompilator wygeneruje błąd. Musisz wiedzieć, że w interfejsach tylko definiujesz metodę, czyli określasz jaki typ zwraca oraz jakie ma parametry. Nie możesz umieszczać żadnych instrukcji wewnątrz nawiasów klamrowych metody, tylko całość kończysz średnikiem. Interfejs tylko i wyłącznie wymaga od klasy, żeby znalazł się w niej zestaw metod identycznych, tzn. zwracała ten sam typ, miała tą samą nazwę, oraz te same parametry! W interfejsach nie możemy ustawić modyfikatora dostępu, gdyż nie ma to najmniejszego sensu, wszystko co znajduje się w interfejsie domyślnie jest publiczne. Z takich ważniejszych rzeczy powinieneś wiedzieć jeszcze, że klasa może miec zaimplementowanych kilka interfejsów, oraz interfejs może dziedziczyć po kolejnych interfejsach. W takich przypadkach wszystkie metody z tych interfejsów muszą znajdować się w klasie, bądź w klasie bazowej(w przypadku gdy dziedziczy). Pamiętaj, że w klasie mogą znajdować się metody, które nie są wymagane przez interfejs.
Wiedząc już nieco o interfejsach wykorzystajmy to w naszym projekcie. Aby zaimplementować interfejs, za nazwą klasy piszemy dwukropek oraz nazwę interfejsu. W przypadku gdy klasa dziedziczy już po jakiejś klasie lub ma zaimplementowany interfejs piszemy przecinek oraz nazwę interfejsu. U nas sytuacja wygląda w ten sposób.
Analogicznie dla Muzyka tworzymy interfejs IMusican oraz implementujemy go do klasy Musican
Interfejs IMusican.cs
1 2 3 4 5 6 7 8 9 10 11 12 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { interface IMusican { } } |
Klasa Musican.cs
Dopiszmy zatem do naszych interfejsów, że wymagamy takich metod, które już się tam znajdują oraz dodajmy do nich po jednej. Dla muzyka dodamy metodę PlayFlute oraz dla tancerza PlaySamba.
Nasze interfejsy powinny wyglądać w ten sposób
Interfejs IMusican.cs
Interfejs IDacer.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { interface IDancer { void DanceBreakdance(); void DanceClassic(); void DanceSamba(); } } |
W momencie dopisania nowych metod do interfejsów pre kompilator zaczął podkreślać nam błąd w klasach, sugerując, że nasza klasa nie zawiera odpowiedniego zestawu, który implementuje interfejs. Dzięki temu interfejs daje nam 100% pewności, że nie zapomnimy o zaimplementowaniu żadnej metody! Obsłużmy zatem nasze nowe metody. Zanim jednak przejdziemy do głównej klasy programu, dopiszmy jeszcze po jednej umiejętności dla profesji, ale już bez dodawania jej do interfejsu oraz napiszmy konstruktory dla naszych klas Musican oraz Dancer, aby kod był przyjaźniejszy dla oka.
Klasa Musican.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { public class Musican: Person , IMusican { public Musican() { } public Musican(string name, int age, int height, int weight) { this.Name = name; this.Age = age; this.Height = height; this.Weight = weight; } //zagraj na skrzypcach public void PlayViolin() { Console.WriteLine("Gram na skrzypcach."); } //zagraj na pianinie public void PlayPiano() { Console.WriteLine("Gram na pianinie."); } public void PlayFlute() { Console.WriteLine("Gram na flecie."); } public void PlayDrum() { Console.WriteLine("Gram na bębnie."); } } } |
Klasa Dancer.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { public class Dancer: Person, IDancer { public Dancer() { } public Dancer(string name, int age, int height, int weight) { this.Name = name; this.Age = age; this.Height = height; this.Weight = weight; } // zatańcz taniec breakdance public void DanceBreakdance() { Console.WriteLine("Tanczę Breakdance."); } // zatancz taniec klasyczny public void DanceClassic() { Console.WriteLine("Tanczę taniec klasyczny."); } public void DanceSamba() { Console.WriteLine("Tanczę Sambę."); } public void DanceSalsa() { Console.WriteLine("Tanczę Salsę"); } } } |
W klasie programu stwórzmy sobie zatem kilku muzyków i tancerzy. A następnie zwróć uwagę jakie kolejne możliwości dają nam interfejsy.
Klasa główna programu Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wiedza_interface { class Program { static void Main(string[] args) { //tworzymy listę ludzi List<Person> persons = new List<Person>(); //tworzymy muzyków Musican m1 = new Musican("Janek",20,190,85); Musican m2 = new Musican("Karol",26,188,82); Musican m3 = new Musican("Krzysiek",32,170,72); //tworzymy tancerzy Dancer d1 = new Dancer("Piotrek",25,185,73); Dancer d2 = new Dancer("Bartek",15,179,67); Dancer d3 = new Dancer("Tomek",17,188,77); //dodajemy wszystkich do listy persons.Add(m1); persons.Add(m2); persons.Add(m3); persons.Add(d1); persons.Add(d2); persons.Add(d3); foreach (Person p in persons) { if (p is IDancer) { IDancer d = p as Dancer; //mamy teraz dostęp tylko do metod zaimplementowancych w interfejsie Console.WriteLine("{0}: ", p.Name); d.DanceBreakdance(); } } Console.ReadKey(); } } } |
Po uruchomieniu programu otrzymamy:
1 2 3 4 5 6 |
Piotrek: Tancze Breakdance. Bartek: Tancze Breakdance. Tomek: Tancze Breakdance. |
W klasie programu, w pętli foreach sprawdzamy czy dany obiekt typu Person implementuje interfejs IDancer(za pomocą instrukcji is) . Jeżeli tak to traktujemy ten obiekt jako implementacje IDancer. Dzięki temu ograniczamy funkcjonalność tylko do metod znajdujących się właśnie w tym interfejsie – kolejny przykład wykorzystania. Pamiętaj również, że nie można tworzyć instancji interfejsu (twórzyc jak obiekt, za pomocą słowa new w odniesieniu do interfejsu, ponieważ metody i właściwości nie mają żadnej implementacji), ale można uzyskać jego referencję (powyższy przykład).