Interfejsy w C#: Twoja broń w walce o czysty kod

Interfejsy w C#: Twoja broń w walce o czysty kod

Interfejsy w C#: Twoja broń w walce o czysty kod

Słyszałeś kiedyś o zasadzie DRY (Don’t Repeat Yourself)? A może o magicznych słowach „czysty kod” i „programowanie obiektowe”? Dzisiaj pokażę Ci, jak interfejsy w C# pomagają osiągnąć te cele w praktyce. Zapnij pasy, bo zanurkujemy w realny problem, z którym spotyka się każdy deweloper: logowanie.

Problem, który znasz z autopsji: Szycie na miarę

Wyobraź sobie, że piszesz aplikację. Chcesz rejestrować ważne informacje: błędy, zdarzenia bezpieczeństwa, a może po prostu dane do analizy biznesowej. Na początku wszystko jest proste. Masz klasę Klient i dodajesz do niej metodę Log(), która zwraca ciąg znaków z informacjami o kliencie. Prawda, że proste?.

// W klasie Klient
public string Log()
{
    var logString = this.KlientId + ": " + this.ImieNazwisko + " " + "Email: " + this.Email;
    return logString;
}

Później dodajesz kolejną klasę, np. Produkt. Robisz dokładnie to samo — dodajesz metodę Log().

// W klasie Produkt
public string Log()
{
    var logString = this.ProduktId + ": " + this.NazwaProduktu + " " + "Opis: " + this.Opis;
    return logString;
}

Świetnie! Teraz każda klasa wie, co chce logować. Ale co, jeśli chcesz zebrać te wszystkie informacje w jednym miejscu? Tworzysz Usługę Logowania z metodą PiszDoPliku(), która przyjmuje listę obiektów, bo przecież możesz logować zarówno klientów, jak i produkty. Początkowo możesz pomyśleć o użyciu List<Object>.

I tu zaczynają się schody. Kiedy w pętli foreach próbujesz wywołać element.Log(), kompilator krzyczy, że Object nie ma takiej metody.

Interfejsy w C#: Elegancja w działaniu

W tym miejscu wkraczają interfejsy. Interfejs to nic innego jak kontrakt. Deklaruje, co dana klasa powinna robić, ale nie mówi, jak ma to zrobić.

Zacznijmy od stworzenia prostego interfejsu o nazwie ILogowanie w folderze Common. Zgodnie z konwencją, interfejsy w C# zaczynają się od wielkiej litery “I”.

// ILogowanie.cs
public interface ILogowanie
{
    string Log();
}

Proste, prawda? Ten interfejs mówi: „Każda klasa, która mnie zaimplementuje, musi mieć publiczną metodę Log(), która zwraca string”. Modyfikator public jest tu niepotrzebny, ponieważ członkowie interfejsu są domyślnie publiczni.

Implementacja Interfejsu: Mów, co robisz i rób, co mówisz

Teraz wracamy do naszych klas Klient i Produkt. Zamiast dodawać metodę Log() ot tak, implementujemy w nich nasz interfejs.

public class Klient : KlasaBazowa, ILogowanie
{
    // ...
}
public class Produkt : KlasaBazowa, ILogowanie
{
    // ...
}

Jeśli klasa już ma metodę Log() zgodną z interfejsem, to super, nic więcej nie musisz robić. Jeśli nie, Visual Studio podpowie Ci, że musisz ją zaimplementować, a nawet wygeneruje kod za Ciebie.

Polimorfizm: Magia za kulisami

I wreszcie nadszedł czas na rozwiązanie naszego problemu logowania! Zamiast używać List<Object>, możemy użyć listy interfejsów: List<ILogowanie>

public static class UslugaLogowanie
{
    public static void PiszDoPliku(List<ILogowanie> zmienioneElementy)
    {
        foreach (var element in zmienioneElementy)
        {
            Console.WriteLine(element.Log());
        }
    }
}

I to jest właśnie polimorfizm w akcji! element w pętli jest traktowany jako typ ILogowanie, co oznacza, że mamy dostęp do jego metody Log(). UslugaLogowanie nie musi wiedzieć, czy loguje klienta, produkt, czy zamówienie. Po prostu wie, że każdy z tych obiektów ma metodę Log().

// 1. Definiowanie interfejsu
public interface ILogowanie
{
    string Log();
}

// 2. Implementacja interfejsu
public class Klient : ILogowanie
{
    public string Imie { get; set; }
    public string Log()
    {
        return $"Logowanie Klienta: {this.Imie}";
    }
}

// 3. Użycie polimorfizmu
public static class UslugaLogowania
{
    public static void Pisz(List<ILogowanie> elementyDoLogowania)
    {
        foreach (var element in elementyDoLogowania)
        {
            Console.WriteLine(element.Log());
        }
    }
}

🎯 Dlaczego to działa?

Bo wykorzystujesz polimorfizm oparty na interfejsie – zamiast pytać „czym jesteś?”, po prostu wołasz Log() i masz wynik.
To esencja programowania obiektowego w C#: mniej zależności, więcej możliwości, czystszy kod.

Dlaczego warto to znać?

Czysty Kod i SOLID

To rozwiązanie jest zgodne z zasadami SOLID, a w szczególności z zasadą pojedynczej odpowiedzialności (każda klasa wie, co logować) i zasadą odwrócenia zależności.

Wielokrotny użytek

UslugaLogowanie jest generyczna i możesz jej używać z każdym obiektem, który implementuje ILogowanie.

Łatwość rozbudowy

Chcesz logować nową klasę, np. Zamowienie? Wystarczy, że zaimplementujesz w niej ILogowanie, a Twoja usługa logowania zadziała bez zmian.

Interfejsy to potężne narzędzie, które pozwala pisać elastyczny, rozszerzalny i czysty kod. Pomyśl o tym jak o planie, który zapewnia spójność w Twojej aplikacji.

🧠 Podsumowanie w 3 punktach

  • Interfejsy jako kontrakty:
    Interfejs definiuje zestaw metod, które klasa musi zaimplementować, bez podawania szczegółów implementacji.
  • Polimorfizm oparty na interfejsach:
    Dzięki interfejsom możesz traktować różne obiekty w uogólniony sposób, co pozwala na tworzenie elastycznych i reużywalnych usług, np. UslugaLogowanie.
  • SOLID w praktyce:
    Użycie interfejsów to klucz do tworzenia solidnych, skalowalnych aplikacji, które łatwo modyfikować i rozszerzać.

C# Podstawy Programowania Obiektowego

To tylko wierzchołek góry lodowej! Jeśli chcesz poznać więcej takich praktycznych i angażujących przykładów, które sprawią, że C# i programowanie obiektowe staną się dla Ciebie naturalne, zapraszam na mój pełny kurs „C# Podstawy Programowania Obiektowego” dostępny na dev-hobby.pl.

🛠 Podsumowanie

🔑 Interfejsy to nie tylko „ładne słówko” – to prawdziwa dźwignia w architekturze aplikacji.

Używaj ich wtedy, gdy chcesz:

  • zbudować wspólny kontrakt dla różnych klas,
  • stworzyć luźne powiązania między komponentami,
  • rozszerzać kod bez jego modyfikowania.

I pamiętaj – logowanie to tylko przykład. To samo podejście wykorzystasz w e-mailach, raportach, walidacji i wszędzie tam, gdzie różne obiekty powinny zachowywać się w podobny sposób.

Masz pytania? Wbij w komentarzach albo napisz do mnie. Wspólnie ogarniemy C# do poziomu zawodowca 💪

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *