Belirgin Arayüzler
Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 28 / 70.
Bir sınıf, aynı isme sahip üyelere sahip birden fazla arayüzü uyguladığında, bir isim çakışmasıyla karşılaşırsınız. Açık arayüz uygulaması (explicit interface implementation), her bir arayüz için ayrı uygulamalar sağlamanıza olanak tanıyarak bu sorunu çözer.
Açık uygulama (explicit implementation) ile, üye adının önüne arayüz adını getirirsiniz ve erişim belirleyicisini atlarsınız:
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");
}
}Açıkça uygulanan üyelere yalnızca arayüz türündeki bir değişken aracılığıyla erişilebilir, sınıfın kendisi üzerinden erişilemez:
var adapter = new UniversalAdapter();
// adapter.Connect(); // Derlenmeyecek!
IAmericanPlug american = adapter;
american.Connect(); // 120V'a bağlandı
IEuropeanPlug european = adapter;
european.Connect(); // 220V'a bağlandıBu teknik, arayüz üyelerini sınıfın genel API'sinden gizlemek istediğinizde de yararlıdır. Bir yöntem yalnızca nesneye belirli bir arayüz olarak yaklaşıldığında anlamlıysa, açık uygulama (explicit implementation) sözleşmeyi yerine getirirken sınıfınızın yüzey alanını temiz tutar.
Görev
KolayAçık arabirim uygulamasının (explicit interface implementation), tek bir sınıfın hangi arabirimin kullanıldığına bağlı olarak nasıl farklı davranışlar sergilemesine izin verdiğini gösteren bir rapor oluşturucu sistemi kuralım. Ekran görüntüsü ve yazdırma için farklı şekilde biçimlendirilebilen bir belge oluşturacaksınız.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
IDisplayable.cs:Reportsad alanı (namespace) içindeIDisplayableadında bir arabirim tanımlayın. Bu arabirim, ekranda gösterilebilen içeriği temsil eder. Geriye bir dize (string) döndürenRender()adında bir metot bildirmelidir.IPrintable.cs:Reportsad alanı içindeIPrintableadında bir arabirim tanımlayın. Bu arabirim, bir yazıcıya gönderilebilen içeriği temsil eder. Bu da geriye bir dize döndürenRender()adında bir metot bildirmelidir - bununIDisplayableile bir isim çakışması yarattığına dikkat edin!Report.cs:Reportsad alanı içinde hemIDisplayablehem deIPrintablearabirimlerini uygulayan birReportsınıfı tanımlayın. Raporun birTitleözelliği (string) ve birContentözelliği (string) olmalı ve her iki değeri de ayarlayan bir yapıcı metodu (constructor) bulunmalıdır. FarklıRender()davranışları sağlamak için açık arabirim uygulamasını kullanın:- Ekran için işlendiğinde:
"[SCREEN] {Title}: {Content}" - Yazdırma için işlendiğinde:
"[PRINT] {Title} | {Content}"
- Ekran için işlendiğinde:
Program.cs: Ana dosyanızda, girdi değerlerini kullanarak birReportnesnesi oluşturun. Açık uygulamalara yalnızca arabirim değişkenleri aracılığıyla erişilebildiğinden, aynı raporu hem birIDisplayabledeğişkeninde hem de birIPrintabledeğişkeninde saklayın, ardından aynı nesnenin hangi arabirimi kullandığınıza bağlı olarak nasıl farklı çıktılar ürettiğini göstermek için her birindeRender()metodunu çağırın.
İki girdi alacaksınız:
- Rapor başlığı
- Rapor içeriği
Çıktıyı şu formatta yazdırın:
Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}Örneğin, girdiler Sales Report ve Q4 revenue increased by 15% ise, çıktı şöyle olmalıdır:
Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%Aynı Report nesnesinin, ona erişmek için hangi arabirim referansını kullandığınıza bağlı olarak nasıl farklı davrandığına dikkat edin. Bu, açık arabirim uygulamasının gücüdür - bağlama uygun davranış sağlarken isim çakışmalarını çözer!
Kopya kağıdı
Bir sınıf, aynı ada sahip üyelere sahip birden fazla arayüzü (interface) uyguladığında, her bir arayüz için ayrı uygulamalar sağlamak amacıyla açık arayüz uygulaması (explicit interface implementation) kullanabilirsiniz.
Bir arayüz üyesini açıkça uygulamak için, üye adının önüne arayüz adını ekleyin ve erişim belirleyicisini (access modifier) kaldırın:
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");
}
}Açıkça uygulanan üyelere yalnızca arayüz türündeki bir değişken aracılığıyla erişilebilir, sınıfın kendisi üzerinden erişilemez:
var adapter = new UniversalAdapter();
// adapter.Connect(); // Derlenmeyecektir!
IAmericanPlug american = adapter;
american.Connect(); // Connected to 120V
IEuropeanPlug european = adapter;
european.Connect(); // Connected to 220VBu teknik şunlar için kullanışlıdır:
- Arayüz üyeleri arasındaki ad çakışmalarını çözmek
- Arayüz üyelerini, yalnızca belirli bir arayüz bağlamında anlamlı olduklarında sınıfın genel API'sinden gizlemek
Kendin dene
using System;
using Reports;
class Program
{
public static void Main(string[] args)
{
// Girdiyi oku
string title = Console.ReadLine();
string content = Console.ReadLine();
// TODO: title ve content ile bir Report nesnesi oluşturun
// TODO: Raporu bir IDisplayable değişkeninde saklayın
// TODO: Aynı raporu bir IPrintable değişkeninde saklayın
// TODO: IDisplayable üzerinde Render() metodunu çağırarak ekran sürümünü yazdırın
Console.WriteLine("Display version:");
// Render sonucunu buraya yazdırın
// TODO: IPrintable üzerinde Render() metodunu çağırarak yazdırma sürümünü yazdırın
Console.WriteLine("Print version:");
// Render sonucunu buraya yazdırın
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici Dosyalarİsim Alanları ve YönergelerSınıf ve Nesnelere Giriş'this' Anahtar KelimesiMetotlar ve ParametrelerAlanlar ve ÖzelliklerYapıcı MetotlarNesne BaşlatıcılarÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (:) Sözdizimi'base' Anahtar KelimesiVirtual ve Override Anahtar KelimeleriSealed Sınıflar'object' Temel SınıfıÖzet - Çalışan Hiyerarşisi7İleri Düzey Özellikler
Operatör Aşırı Yüklemeİndeksleyiciler (this[])ToString() Geçersiz KılmaGenişletme MetotlarıÖzet - Özel Liste10Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişThread-Safe SingletonFactory KalıbıObserver Kalıbı (Olaylar)Strategy Kalıbı2Özellikler ve Statik Üyeler
Otomatik Uygulanan ÖzelliklerSadece Okunur/Yazılır ÖzelliklerStatik Alanlar ve MetotlarStatik Sınıflarİfade Gövdeli Üyeler5Polimorfizm ve Arayüzler
Derleme vs Çalışma Zamanı PolimorfizmiArayüz vs Soyut SınıfÇoklu ArayüzlerBelirgin ArayüzlerUpcasting ve DowncastingÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kalıtım yerine KompozisyonGenerics (Sınıflar ve Metotlar)Delegates ve EventlerAttributes ve ReflectionIDisposable ve using İfadesiDependency Injection Temelleri11Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit Kalıbı3Sınıf Mimarisi
Örnek vs Statik Veri'readonly' ve 'const' Anahtar KelimeleriDestekleyici Alanlar (Backing Fields)Özet - Banka Hesabı Yöneticisi6Kapsülleme
Erişim BelirleyicilerKapsülleme için ÖzelliklerVeri Gizleme UygulamasıDeğişmezlik KalıplarıÖzet - Öğrenci Kayıtları