Kalıtım yerine Kompozisyon
Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 41 / 70.
Kalıtım, sınıflar arasında sıkı bir bağlılık yaratır. Bir Car sınıfı Vehicle sınıfından kalıtım aldığında, Vehicle üzerinde yapılan herhangi bir değişiklik Car sınıfını bozabilir. Kompozisyon daha esnek bir alternatif sunar: bir sınıf, davranışı miras almak yerine, o davranışı sağlayan nesneleri içerir.
Hareket edebilen ve saldırabilen bir oyun karakterini düşünün. Kalıtım ile karmaşık bir hiyerarşi oluşturabilirsiniz. Kompozisyon ile karaktere sadece ihtiyacı olan bileşenleri verirsiniz:
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();
}Temel fark ilişkidir. Kalıtım "is-a" (bir Köpek bir Hayvandır - is an) ilişkisini temsil ederken, kompozisyon "has-a" (bir Karakter hareket davranışına sahiptir) ilişkisini temsil eder. Kompozisyon, çalışma zamanında davranışları değiştirmenize, yetenekleri özgürce birleştirmenize ve kırılgan temel sınıf (fragile base class) probleminden kaçınmanıza olanak tanır.
Gerçek bir hiyerarşik ilişki olduğunda kalıtımı (inheritance) kullanın. Esnekliğe ihtiyaç duyduğunuzda, davranışlar ilişkisiz sınıflar arasında paylaşılabileceğinde veya davranışı dinamik olarak değiştirmek istediğinizde kompozisyonu (composition) seçin.
Görev
KolayKalıtım yerine kompozisyonun (composition over inheritance) gücünü gösteren bir bildirim sistemi oluşturalım. Karmaşık bir bildirim sınıfları hiyerarşisi oluşturmak yerine, bir NotificationSender sınıfını değiştirilebilir davranış bileşenleri vererek oluşturacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
Behaviors.cs:Notificationsad alanı (namespace) içinde, bildirim göndermenin farklı yönlerini ele alan iki davranış sınıfı oluşturun:FormattingBehavior- mesajın başına[ALERT]ve sonuna[END]ekleyerek döndüren birFormat(string message)metoduna sahiptir.DeliveryBehavior-Sending via {channel}: {message}formatında bir dize döndüren birDeliver(string channel, string message)metoduna sahiptir.
NotificationSender.cs:Notificationsad alanı içinde, davranışları birleştirmek için kompozisyon kullanan birNotificationSendersınıfı oluşturun. Göndericiniz şunları yapmalıdır:- Hem
FormattingBehaviorhem deDeliveryBehaviorörneklerini özel alanlar (private fields) olarak içermelidir. - Teslimat kanalı adını saklayan bir
Channelözelliğine (string) sahip olmalıdır. - Kanal adını kabul eden bir yapıcı metoda (constructor) sahip olmalıdır.
- Önce mesajı biçimlendirme davranışını kullanarak biçimlendiren, ardından teslimat davranışını kullanarak kanalla birlikte ileten ve nihai sonucu döndüren bir
Send(string message)metoduna sahip olmalıdır.
- Hem
Program.cs: Ana dosyanızda, girdiden alınan bir kanalla birNotificationSenderoluşturun, ardından girdiden alınan bir mesajı gönderin. Oluşturulan davranışların birlikte nasıl çalıştığını göstermek için sonucu yazdırın.
İki girdi alacaksınız:
- Teslimat kanalı adı (örneğin,
Email,SMS) - Gönderilecek mesaj
Bildirim göndericinizde Send() metodunu çağırmanın sonucunu yazdırın.
Örneğin, girdiler Email ve Server is down ise, çıktı şu şekilde olmalıdır:
Sending via Email: [ALERT] Server is down [END]NotificationSender sınıfının hiçbir şeyden kalıtım almadığına dikkat edin - sadece biçimlendirme ve teslimat davranışlarına "sahiptir". Bu kompozisyon yaklaşımı, gönderici sınıfını değiştirmeden her iki davranışı da kolayca değiştirebileceğiniz veya bu davranışları tamamen farklı sınıflarda yeniden kullanabileceğiniz anlamına gelir!
Kopya kağıdı
Kompozisyon (Bileşim), bir sınıfın bir üst sınıftan davranış miras alması yerine, davranış sağlayan nesneleri içermesini sağlayarak daha esnek kod oluşturan, kalıtıma bir alternatiftir.
Kalıtım vs Kompozisyon:
- Kalıtım "is-a" (bir ...-dır) ilişkilerini temsil eder (bir Köpek bir Hayvandır)
- Kompozisyon "has-a" (bir ...-ya sahiptir) ilişkilerini temsil eder (bir Karakter hareket davranışına sahiptir)
Kompozisyonun Faydaları:
- Çalışma zamanında davranışları değiştirme
- Yetenekleri özgürce birleştirme
- Sıkı bağlılıktan ve kırılgan temel sınıf problemlerinden kaçınma
- İlişkisiz sınıflar arasında davranışları paylaşma
Davranış bileşenleri ile örnek:
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();
}Her bir yaklaşım ne zaman kullanılmalı:
- Gerçek hiyerarşik ilişkiler için kalıtımı kullanın
- Esneklik, paylaşılan davranışlar veya dinamik davranış değişiklikleri için kompozisyonu seçin
Kendin dene
using System;
using Notifications;
class Program
{
public static void Main(string[] args)
{
// Girdiyi oku
string channel = Console.ReadLine();
string message = Console.ReadLine();
// TODO: Kanal ile bir NotificationSender oluştur
// TODO: Mesajı gönder ve sonucu yazdır
}
}
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ı