101 sposobów na interfejsy

101 sposobów na interfejsy

W zależności od doświadczenia nasze spojrzenie na języki programowania i ich funkcjonalności zmienia się diametralnie. Na początku dany język to tylko wiedza ogólna – uczymy się jak deklarować zmienne, jak tworzyć klasy, albo jak realizować dziedziczenie. Wystarczy nam to do tworzenia prostych programów, więc nie spędzamy za dużo czasu na zastanawianiu się czemu ktoś poświęcił swój czas na to, aby w danym języku istniały np. typy generyczne albo dlaczego this działa inaczej niż byliśmy do tego przyzwyczajeni. Dopiero setki godzin wypracowanych z danym językiem (a najlepiej językami) otwierają nasze oczy i zachęcają do rozpracowania jednego, ściśle określonego tematu.

Dla mnie takim tematem stały się interfejsy, które chciałem lepiej zrozumieć w trakcie studiów. Na początku temat ten wydawał się dość… prosty. No bo co – tworzę prosty interfejs, w środku definiuję kilka metod które są z nim powiązane, a na końcu tworzę klasę która go implementuje. A co tyle krzyku?

Jednak z każdą kolejną książką dotyczącą programowania obiektowego i z każdym kolejnym postem znalezionym na blogach temat wydawał się bardziej interesujący.

„Nie programuj pod konkretne implementacje, programuj pod interfejsy” – słyszałem takie zdanie wiele razy. Ale co to w ogóle znaczy? Na początku były to dla mnie tylko puste zdania, jednak kiedy zaczynałem się przyglądać językowi C# który był ze mną przez całe studia to wszystko zaczęło powoli nabierać sensu. IEnumerable? ICommand? IActionResult? Coś z tymi interfejsami musi być, skoro na starcie sam C# i technologie w których pracowałem, takie jak WPF czy ASP.NET MVC bardzo mocno się na nich opierały.

Odpowiedź na wszystkie pytania przyszła – tak jak z większością rzeczy w programowaniu – wraz z nabieraniem doświadczenia i ciągłym zastanawianiem się dlaczego robię coś tak a nie inaczej.

Czymś co pomogło mi zrozumieć zalety korzystania z interfejsów była chociażby praca z kolekcjami i interfejs IEnumerable. Dzięki niemu zrozumiałem, że dana metoda nie zawsze musi wiedzieć wszystko o typie zwracanym bądź o przyjmowanych parametrach. Jeśli parametr będzie używany tylko do iterowania po nim, to wystarczy, że zamiast konkretnego typu użyjemy interfejsu który zawiera metodę (iterator) do poruszania się po kolejnych elementach danej kolekcji (konkretna kolekcja nie jest w tym momencie ważna):

Typem parametru który tutaj przekażemy może być List implementująca ten interfejs, albo może to być jakakolwiek inna klasa implementująca IEnumerable<int>. Z perspektywy naszego „algorytmu” do obliczania ceny całkowitej nie interesuje nas konkretny typ – chcemy jedynie mieć gwarancję, że iterowanie po wszystkich elementach będzie możliwe. Interfejs sprawdza się tutaj znakomicie – sugeruje sposób wykorzystania parametru, ale nie narzuca konkretnego typu czy implementacji.

W docenieniu interfejsów bardzo mocno pomagają też wzorce projektowe – poniżej jeden z moich ulubionych czyli strategia. Dzięki strategii możemy w trakcie działania programu podmieniać sposób zachowania danego obiektu – wszystko dzięki zastosowaniu interfejsu do zdefiniowania ogólnych założeń, a następnie zaimplementowania go w konkretnych klasach:

Nasza klasa Person będzie potrzebować „czegoś” do przedstawienia się. Aby odwzorować realne zachowanie ludzi możemy mechanizm „mówienia” opakować w interfejs i zaimplementować go na dwa różne sposoby. Dzięki temu w zależności od nastroju nasz człowiek będzie mówił po cichu albo zdecydowanie głośniej.

I także w tym przykładzie interfejs pokazuje swoją siłę – instancja klasy Person nie musi mieć ściśle określonego i powiązanego ze sobą „sposobu wyrażania się” dzięki wykorzystaniu interfejsu ISpeaker. Być może dzisiaj mamy tylko dwie klasy które go implementują, ale w przyszłości może dojść trzecia, czwarta albo dziesiąta – wszystko będzie działać poprawnie dopóki będą one implementować ten sam interfejs. Do tego klasa Person zostanie nienaruszona, a jak wiadomo mniej zmian w kodzie to i mniejsze ryzyko popełnienia błędu.

 

Temat interfejsów i ich przykładów ich wykorzystania jest tak rozległy, że być może w przyszłości poświęcimy mu zdecydowanie więcej miejsca. Dzisiaj na dokładkę przedstawiamy wam prezentację, którą przygotowałem w trakcie studiów na jedno ze spotkań koła informatycznego.

Starałem się tam umieścić najważniejsze informacje dotyczące interfejsów na podstawie języka C#, pokazałem różnicę pomiędzy kompozycją a dziedziczeniem, a także stworzyłem projekt w którym pokazuję wszystko w praktyce:

Przykłady które powstały na potrzeby tej prezentacji możecie znaleźć na moim GitHubowym profilu: https://github.com/psmyrdek/ResetInterfejsy

Jeśli do tej pory nie mieliście okazji wykorzystać interfejsów w swoich projektach to zdecydowanie do tego zachęcam. Ci z was, którzy mają za sobą komercyjne projekty na pewno potwierdzą, że interfejsy to nie napompowany, marketingowy balon tylko koncept który przynosi programistom realne korzyści.

Jeśli macie na ich temat jakieś konkretne zdanie bądź uważacie, że interfejsy wcale nie są tak pomocne jak mogłoby się wydawać, to koniecznie dodajcie swoją opinię w komentarzach – zachęcamy do dyskusji!