Menu
Coddy logo textTech

Kompozycja zamiast dziedziczenia

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 41 z 70.

Dziedziczenie tworzy silne powiązania między klasami. Gdy Car dziedziczy po Vehicle, każda zmiana w Vehicle może zepsuć Car. Kompozycja oferuje bardziej elastyczną alternatywę: zamiast dziedziczyć zachowanie, klasa zawiera obiekty, które je zapewniają.

Rozważ postać z gry, która może się poruszać i atakować. Dzięki dziedziczeniu możesz stworzyć złożoną hierarchię. Dzięki kompozycji po prostu przypisujesz postaci potrzebne jej komponenty:

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

Kluczowa różnica dotyczy relacji. Dziedziczenie reprezentuje relację „jest” (Dog jest Animal), natomiast kompozycja reprezentuje relację „ma” (Character ma zachowanie związane z ruchem). Kompozycja pozwala wymieniać zachowania w czasie działania programu, swobodnie łączyć możliwości i unikać problemu kruchej klasy bazowej.

Używaj dziedziczenia, gdy istnieje rzeczywista relacja hierarchiczna. Wybieraj kompozycję, gdy potrzebujesz elastyczności, gdy zachowania mogą być współdzielone przez niepowiązane klasy lub gdy chcesz dynamicznie zmieniać zachowanie.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system powiadomień, który pokazuje zalety kompozycji nad dziedziczeniem. Zamiast tworzyć złożoną hierarchię klas powiadomień, utworzysz obiekt NotificationSender, wyposażając go w wymienne komponenty zachowania.

Rozmieścisz swój kod w trzech plikach:

  • Behaviors.cs: Utwórz dwie klasy zachowań w przestrzeni nazw Notifications, które obsługują różne aspekty wysyłania powiadomień:
    • FormattingBehavior — ma metodę Format(string message), która zwraca komunikat otoczony przez [ALERT] na początku i [END] na końcu
    • DeliveryBehavior — ma metodę Deliver(string channel, string message), która zwraca ciąg znaków w formacie Sending via {channel}: {message}
  • NotificationSender.cs: Utwórz klasę NotificationSender w przestrzeni nazw Notifications, która łączy zachowania za pomocą kompozycji. Twój obiekt nadawcy powinien:
    • Zawierać instancje zarówno FormattingBehavior, jak i DeliveryBehavior jako pola prywatne
    • Mieć właściwość Channel (string), która przechowuje nazwę kanału dostarczania
    • Mieć konstruktor, który przyjmuje nazwę kanału
    • Mieć metodę Send(string message), która najpierw formatuje komunikat za pomocą zachowania formatującego, następnie dostarcza go za pomocą zachowania dostarczającego i zwraca końcowy wynik
  • Program.cs: W pliku głównym utwórz obiekt NotificationSender z kanałem pobranym z wejścia, a następnie wyślij komunikat pobrany z wejścia. Wypisz wynik, aby pokazać, jak współdziałają połączone zachowania.

Otrzymasz dwa dane wejściowe:

  • Nazwę kanału dostarczania (np. Email, SMS)
  • Komunikat do wysłania

Wypisz wynik wywołania Send() na obiekcie nadawcy powiadomień.

Na przykład, jeśli danymi wejściowymi są Email i Server is down, wynikiem powinno być:

Sending via Email: [ALERT] Server is down [END]

Zauważ, że NotificationSender nie dziedziczy po żadnej klasie — po prostu „ma” zachowania formatujące i dostarczające. Takie podejście oparte na kompozycji oznacza, że możesz łatwo wymienić dowolne z tych zachowań bez zmieniania klasy nadawcy albo wykorzystać je ponownie w zupełnie innych klasach!

Spróbuj swoich sił

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // Odczytaj dane wejściowe
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Utwórz NotificationSender z podanym kanałem
        
        // TODO: Wyślij wiadomość i wypisz wynik
        
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C# online