Ana içeriğe geç

Yan yana

BileşimvsKalıtım

Bileşim (composition) ile kalıtım (inheritance) arasındaki fark nedir?

Güncellendi 3 dk okuma8 fark

Kısaca

Bileşim, kodu başka nesneleri tutup işi onlara devrederek yeniden kullanır (has-a); kalıtım ise bir üst sınıfı genişleterek yeniden kullanır (is-a).

Bileşim

Bileşim, bir nesneyi tuttuğu ve işi devrettiği başka nesnelerden kurar; bir üst sınıftan kalıtım almak yerine “sahiptir” (has-a) ilişkisini modeller.

Bileşim sayfasını oku

Kalıtım

Kalıtım, yeni bir sınıfın mevcut bir sınıfın alanlarını ve metotlarını yeniden kullanmasını, genişletmesini ve geçersiz kılmasını sağlayan OOP özelliğidir.

Kalıtım sayfasını oku

Bileşim ve Kalıtım karşılaştırması

ÖzellikBileşimKalıtım
İlişkiSahiptir (has-a): bir arabanın motoru vardır-dir (is-a): bir köpek bir hayvandır
Kodun yeniden kullanımıAlanlarda tutulan nesnelere çağrıları devrederekBir üst sınıfın alanlarını ve metotlarını miras alarak
BağımlılıkGevşek: yalnızca parçaların interface'lerine bağlıdırSıkı: alt sınıf ebeveyninin iç yapısına bağlıdır
Ne zaman sabitlendiğiParçalar çalışma zamanında seçilebilir ya da testlerde değiştirilebilirSınıf yazıldığında sabitlenir
Özellikleri birleştirmekBir motor ve bir sürücü gibi parçalar serbestçe karıştırılırHer birleşim kendi alt sınıfını gerektirebilir
Kod miktarıDaha fazla: işi devreden her metot tek tek yazılırDaha az: miras alınan metotlar hazır gelir
Çok biçimlilikOrtak interface'ler üzerindenEbeveynin metotlarını geçersiz kılarak
Dil desteğiHer dil; Go ve Kotlin yerleşik kolaylıklar eklerÇoğu OOP dili; Go'da sınıf kalıtımı yoktur

Fark, açıklamalı

Bileşim ve kalıtım, nesne yönelimli programlamada kodu yeniden kullanmanın iki ana yoludur. Bileşim bir sınıfı, alanlarında tuttuğu ve işi devrettiği başka nesnelerden kurar ve “sahiptir” (has-a) ilişkisini modeller: bir Car bir Engine'e sahiptir. Kalıtım ise var olan bir sınıftan yeni bir sınıf oluşturur; yeni sınıf ebeveynin alanlarını ve metotlarını alır, onları geçersiz kılabilir ve “-dir” (is-a) ilişkisini modeller: bir Dog bir Animal'dır.

Asıl fark bağımlılığın sıkılığındadır (coupling). Bir alt sınıf ebeveyninin iç yapısına bağlıdır; bu yüzden ebeveyndeki bir değişiklik bütün alt sınıfları bozabilir ve hiyerarşi kod yazılırken sabitlenir. Özellikler birleştikçe alt sınıflar ElectricCar, HybridCar ve SelfDrivingElectricCar diye çoğalır. Bileşimde ise parçalar genellikle interface'lerin arkasında durur; böylece çalışma zamanında seçilebilir, değiştirilebilir ya da testlerde sahteleriyle yer değiştirebilir. Bedeli biraz daha fazla koddur, çünkü işi devreden her metodun yazılması gerekir.

“Sınıf kalıtımı yerine nesne bileşimini tercih edin” ilkesi, Dörtlü Çete'nin (Gang of Four) 1994 tarihli Design Patterns kitabından gelir; strategy, decorator ve dependency injection gibi desenler de bu ilkenin üzerine kuruludur. Bu bir yasak değil, bir tercihtir: kalıtım, Error sınıfını genişleten özel bir hata türü gibi gerçek “-dir” ilişkileri için doğru araç olmayı sürdürür ve gerçek tasarımların çoğu ikisini birlikte kullanır: küçük bir temel sınıftan kalıtım alır ya da bir interface uygular, geri kalanını bileşimle kurar. Bazı diller tasarımları gereği bileşime yaslanır: Go'da sınıf kalıtımı yoktur, onun yerine struct'lar iç içe gömülür; Kotlin ise by ile bütün bir interface'i bir alana devreder.

Sık yapılan bir yanlış, çok biçimlilik (polymorphism) için kalıtımın gerekli olduğu düşüncesidir. Interface'ler, farklı nesnelere aynı şekilde davranma imkânını kod paylaşmadan da sağlar. Bir başkası, kalıtımın işe yarar bir metodu yeniden kullanmanın iyi bir yolu olduğu düşüncesidir; bir sınıfı yalnızca kodu için genişletmek, bileşimin kaçındığı sıkı bağlılığı yaratır. Basit test tek bir sorudur: bu bir X çeşidi mi, yoksa bir X'e sahip mi ya da bir X kullanıyor mu?

Hangisini kullanmalısınız?

Bileşim şu durumlarda doğru seçim:

  • Bir nesne, bir araba ve motoru gibi, başka bir nesneye sahip ya da onu kullanıyor.
  • Davranışın çalışma zamanında değiştirilebilmesi ya da testlerde sahtesiyle değiştirilmesi gerekiyor.
  • Özellikler, alt sınıfları çoğaltacak pek çok şekilde birleşiyor.
  • Kontrol etmediğiniz bir sınıfı, iç yapısına bağlanmadan yeniden kullanmak istiyorsunuz.

Kalıtım şu durumlarda doğru seçim:

  • Bir tür gerçekten başka bir türün bir çeşidi ve ebeveynin beklendiği her yerde kullanılabilir.
  • Bir framework, Error ya da bir arayüz bileşeni sınıfı gibi kendi temel sınıfını genişletmenizi bekliyor.
  • Hiyerarşi sığ ve kararlı; alt sınıflar ebeveynin kodunun çoğunu paylaşıyor.

Farklı motorlu arabalar, iki yolla (TypeScript)

Bileşimtypescript
// Composition: a Car HAS an engine and delegates to it
interface Engine { start(): string; }
class PetrolEngine implements Engine { start() { return "vroom"; } }
class ElectricEngine implements Engine { start() { return "hum"; } }

class Car {
  constructor(private engine: Engine) {}
  start() { return `Car: ${this.engine.start()}`; }
}

new Car(new ElectricEngine()).start(); // "Car: hum", any engine fits
Kalıtımtypescript
// Inheritance: each kind of car IS a Car and overrides a method
class Car {
  start() { return `Car: ${this.sound()}`; }
  protected sound() { return "..."; }
}
class PetrolCar extends Car { protected sound() { return "vroom"; } }
class ElectricCar extends Car { protected sound() { return "hum"; } }

// Every new combination needs another subclass
class SelfDrivingElectricCar extends ElectricCar { /* ... */ }

new ElectricCar().start(); // "Car: hum"

Sık sorulan sorular

“Kalıtım yerine bileşim” ne anlama gelir?

Bir tasarım kılavuzudur: bir davranışı yeniden kullanmak için, o davranışa sahip bir sınıfı genişletmek yerine onu sağlayan bir nesneyi tutmayı tercih edin. Kalıtım yasak değildir; gerçek “-dir” ilişkileri için saklanır.

Kalıtım kötü mü?

Hayır. Bir tür gerçekten başka bir türün bir çeşidiyse ve hiyerarşi sığ kalıyorsa doğru araçtır. Sorunlar derin ağaçlardan ve yalnızca kodu yeniden kullanmak için kalıtım almaktan çıkar.

Go kalıtım olmadan nasıl çalışır?

Go'da sınıf yoktur. Bir struct'ı başka bir struct'ın içine gömer; bu, gömülen türün metotlarını dıştaki türde kullanılabilir kılar. Çok biçimlilik için de interface'leri kullanır; yani yeniden kullanım bileşim yoluyla olur.

Daha fazla

Ayarlar