Menu
Coddy logo textTech

Jawne implementowanie interfejsów

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

Gdy klasa implementuje wiele interfejsów, które mają składowe o tej samej nazwie, dochodzi do konfliktu nazw. Jawna implementacja interfejsu rozwiązuje ten problem, umożliwiając podanie osobnych implementacji dla każdego interfejsu.

W przypadku jawnej implementacji dodaj przed nazwą składowej nazwę interfejsu i pomiń modyfikator dostępu:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

Jawnie zaimplementowane elementy członkowskie są dostępne wyłącznie za pośrednictwem zmiennej typu interfejsu, a nie bezpośrednio przez klasę:

var adapter = new UniversalAdapter();
// adapter.Connect();  // Nie skompiluje się!

IAmericanPlug american = adapter;
american.Connect();  // Podłączono do 120V

IEuropeanPlug european = adapter;
european.Connect();  // Podłączono do 220V

Ta technika jest również przydatna, gdy chcesz ukryć składowe interfejsu przed publicznym API klasy. Jeśli metoda ma sens tylko wtedy, gdy traktujesz obiekt jako konkretny interfejs, jawna implementacja pozwala zachować przejrzystość klasy, a jednocześnie spełnić wymagania kontraktu.

challenge icon

Wyzwanie

Łatwy

Stwórzmy system generowania raportów, który pokazuje, jak jawna implementacja interfejsu pozwala jednej klasie zapewniać różne zachowania w zależności od używanego interfejsu. Utworzysz dokument, który można formatować inaczej do wyświetlania i do drukowania.

Rozmieścisz kod w czterech plikach:

  • IDisplayable.cs: Zdefiniuj interfejs o nazwie IDisplayable w przestrzeni nazw Reports. Ten interfejs reprezentuje zawartość, którą można wyświetlić na ekranie. Powinien deklarować metodę Render(), która zwraca ciąg znaków.
  • IPrintable.cs: Zdefiniuj interfejs o nazwie IPrintable w przestrzeni nazw Reports. Ten interfejs reprezentuje zawartość, którą można wysłać do drukarki. Powinien również deklarować metodę Render(), która zwraca ciąg znaków — zauważ, że powoduje to konflikt nazw z IDisplayable!
  • Report.cs: Zdefiniuj klasę Report w przestrzeni nazw Reports, która implementuje zarówno IDisplayable, jak i IPrintable. Raport powinien mieć właściwość Title (typu string) i właściwość Content (typu string), a także konstruktor, który ustawia obie wartości. Użyj jawnej implementacji interfejsu, aby zapewnić różne zachowania metody Render():
    • Podczas renderowania do wyświetlenia: "[SCREEN] {Title}: {Content}"
    • Podczas renderowania do drukowania: "[PRINT] {Title} | {Content}"
  • Program.cs: W pliku głównym utwórz obiekt Report na podstawie wartości wejściowych. Ponieważ dostęp do jawnych implementacji jest możliwy wyłącznie przez zmienne interfejsowe, przechowaj ten sam raport w zmiennej typu IDisplayable oraz w zmiennej typu IPrintable, a następnie wywołaj na każdej z nich metodę Render(), aby pokazać, jak ten sam obiekt generuje różne wyniki w zależności od używanego interfejsu.

Otrzymasz dwa dane wejściowe:

  • Tytuł raportu
  • Treść raportu

Wypisz wynik w tym formacie:

Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}

Na przykład, jeśli danymi wejściowymi są Sales Report i Q4 revenue increased by 15%, wynikiem powinno być:

Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%

Zauważ, że ten sam obiekt Report zachowuje się inaczej w zależności od tego, którego odwołania do interfejsu używasz, aby uzyskać do niego dostęp. Na tym polega siła jawnej implementacji interfejsu — rozwiązuje konflikty nazw, zapewniając jednocześnie zachowanie dostosowane do kontekstu!

Spróbuj swoich sił

using System;
using Reports;

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

        // TODO: Utwórz obiekt Report z tytułem i treścią

        // TODO: Przypisz raport do zmiennej typu IDisplayable

        // TODO: Przypisz ten sam raport do zmiennej typu IPrintable

        // TODO: Wypisz wersję do wyświetlenia, wywołując Render() na IDisplayable
        Console.WriteLine("Display version:");
        // Wypisz tutaj wynik Render()

        // TODO: Wypisz wersję do druku, wywołując Render() na IPrintable
        Console.WriteLine("Print version:");
        // Wypisz tutaj wynik Render()
    }
}
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