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 220VTa 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.
Wyzwanie
ŁatwyStwó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 nazwieIDisplayablew przestrzeni nazwReports. 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 nazwieIPrintablew przestrzeni nazwReports. 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 zIDisplayable!Report.cs: Zdefiniuj klasęReportw przestrzeni nazwReports, która implementuje zarównoIDisplayable, jak iIPrintable. 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 metodyRender():- Podczas renderowania do wyświetlenia:
"[SCREEN] {Title}: {Content}" - Podczas renderowania do drukowania:
"[PRINT] {Title} | {Content}"
- Podczas renderowania do wyświetlenia:
Program.cs: W pliku głównym utwórz obiektReportna 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 typuIDisplayableoraz w zmiennej typuIPrintable, 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()
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online