Arayüz vs Soyut Sınıf
Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 26 / 70.
Hem arayüzler hem de soyut sınıflar, diğer sınıfların uyması gereken sözleşmeler tanımlamanıza olanak tanır, ancak farklı amaçlara hizmet ederler ve farklı yeteneklere sahiptirler.
Bir arayüz (interface), herhangi bir uygulama içermeden bir sınıfın ne yapması gerektiğini tanımlar. Bu saf bir sözleşmedir:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}Bir soyut sınıf (abstract class) hem bir sözleşme hem de paylaşılan bir uygulama sağlayabilir. Bu, kısmi bir taslaktır:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Uygulanmalıdır
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}Temel farklar kalıtım kurallarına ve amaca dayanmaktadır.
Bir sınıf birden fazla arayüzü uygulayabilir ancak yalnızca bir soyut sınıftan miras alabilir.
İlişkisiz sınıfların bir davranışı paylaşması gerektiğinde bir arayüz (interface) kullanın (kuşlar ve uçaklar için IFlyable gibi). İlişkili sınıflar ortak kod ve durumu paylaştığında bir soyut sınıf (abstract class) kullanın (motor çalıştırma mekanizmasını paylaşan taşıtlar gibi).
Soyut sınıflar; yapıcılara, alanlara ve üyeler üzerinde erişim belirleyicilerine sahip olabilir. Geleneksel olarak arayüzler buna sahip olamazdı, ancak modern C# varsayılan uygulamalara izin verir.
Şüpheye düştüğünüzde, esneklik için arayüzleri (interfaces) tercih edin; paylaşılan bir uygulama (shared implementation) gerekli hale gelirse daha sonra her zaman bir soyut sınıf (abstract class) ekleyebilirsiniz.
Görev
KolayArayüzlerin (interfaces) soyut sınıflara (abstract classes) karşı ne zaman kullanılacağını gösteren bir medya oynatıcı sistemi oluşturalım. Birbirinden bağımsız cihazların bir arayüz aracılığıyla oynatma davranışını paylaştığı, ilişkili medya türlerinin ise bir soyut sınıf aracılığıyla ortak uygulamayı paylaştığı bir tasarım oluşturacaksınız.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
IPlayable.cs:Mediaad alanı (namespace) içindeIPlayableadında bir arayüz tanımlayın. Bu arayüz, ister bir telefon, ister bir TV veya özel bir müzik çalar olsun, medya oynatabilen her şey için sözleşmeyi temsil eder. Geriye bir dize (string) döndüren tek birPlay()metodu bildirmelidir.MediaFile.cs:Mediaad alanı içindeMediaFileadında soyut bir sınıf tanımlayın. Bu, tüm medya dosyaları için paylaşılan temeli temsil eder. BirTitleözelliğine (string) ve birDurationözelliğine (int, saniyeyi temsil eder) sahip olmalıdır. Her iki değeri de ayarlayan bir yapıcı (constructor) ekleyin."{Title} ({Duration}s)"döndürenGetInfo()adında somut bir metot ekleyin. Ayrıca, bir dize döndüren soyut birGetType()metodu bildirin - her medya türü ne tür bir dosya olduğunu kendisi tanımlayacaktır.AudioFile.cs:Mediaad alanı içindeMediaFilesınıfından miras alan veIPlayablearayüzünü uygulayan birAudioFilesınıfı tanımlayın. BirArtistözelliği (string) ekleyin. Yapıcı; başlık, süre ve sanatçı bilgilerini kabul etmelidir.GetType()metodunu"Audio"döndürecek şekilde geçersiz kılın (override).Play()metodunu"Playing audio: {Title} by {Artist}"döndürecek şekilde uygulayın.Program.cs: Ana dosyanızda, girdi değerlerini kullanarak birAudioFileoluşturun. Sınıfın her iki yönünü de gösterin:GetInfo()veGetType()metodlarını (soyut sınıftan miras alınan) çağırın, ardındanPlay()metodunu (arayüzden gelen) çağırın. Ses dosyasını birIPlayabledeğişkeninde saklayın ve arayüz polimorfizmini göstermek içinPlay()metodunu tekrar çağırın.
Üç girdi alacaksınız:
- Şarkı adı
- Saniye cinsinden süre
- Sanatçı adı
Çıktıyı şu formatta yazdırın:
Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}Örneğin, girdiler Bohemian Rhapsody, 354 ve Queen ise çıktı şöyle olmalıdır:
Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by QueenAudioFile sınıfının her iki yaklaşımdan da nasıl yararlandığına dikkat edin: Soyut sınıftan paylaşılan uygulamayı (GetInfo()) miras alırken aynı zamanda IPlayable sözleşmesini de yerine getirir. Soyut sınıf, ilgili medya türleri için kodun yeniden kullanılmasını sağlarken, arayüz herhangi bir ilgisiz sınıfın bir kalıtım hiyerarşisini paylaşmadan "oynatılabilir" (playable) olmasına olanak tanır.
Kopya kağıdı
Bir arayüz (interface), sınıfların uyması gereken bir sözleşmeyi herhangi bir uygulama (implementation) içermeden tanımlar:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}Bir soyut sınıf (abstract class), hem bir sözleşme hem de paylaşılan bir uygulama sağlar:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Must be implemented
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}Temel farklar:
- Bir sınıf birden fazla arayüzü uygulayabilir ancak yalnızca bir soyut sınıftan miras alabilir
- İlişkisiz sınıfların bir davranışı paylaşması gerektiğinde arayüzleri kullanın
- İlişkili sınıflar ortak kod ve durumu paylaştığında soyut sınıfları kullanın
- Soyut sınıflar yapıcılara (constructors), alanlara (fields) ve erişim belirleyicilere (access modifiers) sahip olabilir
- Esneklik için arayüzleri tercih edin
Kendin dene
using System;
using Media;
class Program
{
public static void Main(string[] args)
{
// Giriş değerlerini oku
string title = Console.ReadLine();
int duration = Convert.ToInt32(Console.ReadLine());
string artist = Console.ReadLine();
// TODO: Giriş değerlerini kullanarak bir AudioFile oluşturun
// TODO: Info: yazdırın ve ardından GetInfo() sonucunu ekleyin
// TODO: Type: yazdırın ve ardından GetType() sonucunu ekleyin
// TODO: Direct: yazdırın ve ardından Play() sonucunu ekleyin
// TODO: Ses dosyasını bir IPlayable değişkeninde saklayın
// TODO: Via Interface: yazdırın ve ardından IPlayable değişkeninden gelen Play() sonucunu ekleyin
}
}
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ı