Kompozisyon ve Kalıtım
Coddy'nin Dart Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 82 / 110.
Kalıtımın bir "is-a" (bir ...-dır) ilişkisi oluşturduğunu öğrendiniz - bir Dog bir Animal'dır. Ancak başka bir güçlü yaklaşım daha var: "has-a" (sahiptir) ilişkisi oluşturan kompozisyon (composition). Davranışı miras almak yerine, bir sınıf diğer sınıfların örneklerini içerir ve işi onlara devreder.
Bir Car sınıfını ele alalım. Kalıtım ile, bir Engine sınıfını genişletmeyi deneyebilirsiniz - ancak bir araba bir motor değildir, bir motora sahiptir:
class Engine {
void start() => print('Engine started');
}
class Car {
final Engine _engine = Engine(); // Kompozisyon: Araba bir Motora SAHİPTİR
void start() {
_engine.start(); // Görevi motora devret
print('Car is ready to drive');
}
}
void main() {
var car = Car();
car.start();
}Kompozisyonun temel avantajı esnekliktir. Kalıtım ile tek bir üst sınıfa kilitlenirsiniz. Kompozisyon ile birden fazla bileşeni birleştirebilir ve hatta bunları çalışma zamanında değiştirebilirsiniz:
class ElectricEngine {
void start() => print('Electric motor humming');
}
class HybridCar {
Engine? _gasEngine;
ElectricEngine? _electricEngine;
HybridCar({bool useElectric = false}) {
if (useElectric) {
_electricEngine = ElectricEngine();
} else {
_gasEngine = Engine();
}
}
}Yaygın bir ilke "kalıtım yerine kompozisyonu tercih et" şeklindedir. Gerçek bir "is-a" ilişkisi olduğunda ve polimorfizme ihtiyaç duyduğunuzda kalıtımı kullanın. Sıkı bağlılık (tight coupling) olmadan davranışı yeniden kullanmak istediğinizde veya bir nesnenin birden fazla kaynaktan yeteneklere ihtiyacı olduğunda kompozisyonu kullanın.
Görev
KolayKompozisyon (composition) kullanarak bir bilgisayar sistemi inşa edelim! Bir bilgisayarı parçalarından miras alacak şekilde tasarlamak yerine, ayrı bileşen sınıfları oluşturacak ve bunları bir araya getireceksiniz - çünkü bir bilgisayarın bir CPU'su vardır ve belleği vardır, kendisi bir CPU veya bellek değildir.
Kodunuzu üç dosyada organize edeceksiniz:
components.dart: Bilgisayar parçalarını temsil eden iki bileşen sınıfı oluşturun:String brandvedouble speedGHzalanlarına sahip birCPUsınıfı. Şu dizeyi döndüren birprocess()metodu ekleyin:'$brand processing at ${speedGHz}GHz'int sizeGBalanına sahip birMemorysınıfı. Şu dizeyi döndüren birload()metodu ekleyin:'Loading ${sizeGB}GB of data'
computer.dart: Bileşenleri birleştirmek için kompozisyon kullanan birComputersınıfı oluşturun. Bilgisayarınız şunları yapmalıdır:- Bir
String namealanına sahip olmalı - Bir
CPUve birMemoryörneği içermeli (kompozisyon - bilgisayar bu parçalara SAHİPTİR) - Her iki bileşeni de dahili olarak oluşturmak için gerekli tüm değerleri yapıcı metodu (constructor) aracılığıyla kabul etmeli
- Her iki bileşene görev devreden ve üç satır yazdıran bir
boot()metoduna sahip olmalı: bilgisayarın adı ve ardından' starting...', sonra CPU'nun process metodunun sonucu, ardından Memory'nin load metodunun sonucu - Sistemi tanımlayan bir dize döndüren
specs()metoduna sahip olmalı:'$name: ${cpu.brand} ${cpu.speedGHz}GHz, ${memory.sizeGB}GB RAM'
- Bir
main.dart: Dosyalarınızı içe aktarın ve kompozisyonun işleyişini gösterin:3.5GHz hızında çalışan bir'Intel'CPU'ya ve16GB belleğe sahip,'Workstation'adında birComputeroluşturunboot()metodunu çağırınspecs()metodunun sonucunu yazdırın
Computer sınıfının CPU veya Memory sınıflarını genişletmediğine (extend), aksine onları içerdiğine ve işi onlara devrettiğine dikkat edin. Bu, kompozisyonun oluşturduğu "has-a" (sahip olma) ilişkisidir!
Beklenen çıktı:
Workstation starting...
Intel processing at 3.5GHz
Loading 16GB of data
Workstation: Intel 3.5GHz, 16GB RAMKopya kağıdı
Kompozisyon (Composition), bir sınıfın diğer sınıflardan miras almak yerine, diğer sınıfların örneklerini içerdiği ve işi onlara devrettiği bir "has-a" (sahip olma) ilişkisi oluşturur.
Temel kompozisyon örneği:
class Engine {
void start() => print('Engine started');
}
class Car {
final Engine _engine = Engine(); // Car HAS an Engine
void start() {
_engine.start(); // Delegate to the engine
print('Car is ready to drive');
}
}Esneklik sağlayan kompozisyon - bileşenleri değiştirme:
class ElectricEngine {
void start() => print('Electric motor humming');
}
class HybridCar {
Engine? _gasEngine;
ElectricEngine? _electricEngine;
HybridCar({bool useElectric = false}) {
if (useElectric) {
_electricEngine = ElectricEngine();
} else {
_gasEngine = Engine();
}
}
}Kompozisyon ve kalıtım ne zaman kullanılır:
- Polimorfizme ihtiyaç duyduğunuz gerçek "is-a" (bir ...-dır) ilişkileri için kalıtımı (inheritance) kullanın
- Davranışı sıkı bağlılık (tight coupling) olmadan yeniden kullanmak için veya bir nesnenin birden fazla kaynaktan yeteneklere ihtiyacı olduğunda kompozisyonu (composition) kullanın
- Genel kural: "kalıtım yerine kompozisyonu tercih edin"
Kendin dene
import 'computer.dart';
void main() {
// TODO: Şunlara sahip "Workstation" adında bir Computer oluşturun:
// - 3.5 GHz hızında çalışan Intel CPU
// - 16 GB bellek
// TODO: boot() metodunu çağırın
// TODO: specs() sonucunu 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 DosyalarKütüphaneler ve ImportlarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarÖrnek DeğişkenleriConstructor TemelleriÖzet - Basit Hesap Makinesi4Null Safety
Null Safety'ye GirişNullable ve Non-Nullable? ve ! OperatörleriLate Anahtar Kelimesi ve Null SafetyNull-Aware OperatörleriSınıflarda Null SafetyÖzet - Kullanıcı Profili Sistemi7Soyut Sınıflar ve Arayüzler
Soyut SınıflarSoyut MetotlarDart'ta ArayüzlerÖrtük ArayüzlerUygulama vs. GenişletmeÇoklu ArayüzlerÖzet - Şekil Hesaplayıcı10Koleksiyonlar ve Generic'ler
List, Set, Map Genel BakışTip Güvenli KoleksiyonlarGeneric SınıflarGeneric MetotlarGeneric KısıtlamalarIterable ve IteratorÖzet - Generic Depolama13İleri Düzey OOP Kavramları
Kompozisyon ve KalıtımExtension MetotlarÇağrılabilir SınıflarSealed Sınıflar (Dart 3)Records (Dart 3)Desenler ve Eşleştirme (3.0)Metot İçeren Enum'lar2Dart'ta Yapıcılar
Varsayılan Yapıcıİsimlendirilmiş Yapıcılarİlklendirme ListeleriSabit YapıcılarFabrika YapıcılarıYönlendiren YapıcılarÖzet - Şekil Oluşturucu5Kapsülleme
Public ve Private Üyeler_ Öneki KuralıKütüphane Düzeyinde GizlilikGetter ve Setter DetaylarıBilgi GizlemeÖzet - Öğrenci Kayıtları8Mixin'ler
Mixin'lere GirişMixin OluşturmaBirden Fazla Mixin KullanımıMixin'lerde on Anahtar KelimesiMixin vs KalıtımMixin vs ArayüzÖzet - Hayvan Sistemi11Özel Metotlar
toString() OverridehashCode ve == OverrideComparable Arayüzücall() MetodunoSuchMethod OverrideÖzet - Özel Koleksiyon14Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı17Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakter SistemiAraç Kiralama Servisi3Sınıf Özellikleri
Instance ve Statik ÜyelerFinal ve Const AlanlarLate DeğişkenlerStatik Metotlar ve AlanlarGetters ve SettersÖzet - Banka Hesabı Yöneticisi6Kalıtım
Temel Kalıtımsuper Anahtar KelimesiMetot Ezme@override Anotasyonufinal Sınıf Anahtar KelimesiYapıcı Metotlar ve KalıtımÖzet - Çalışan Hiyerarşisi9Çok Biçimlilik
Çok Biçimlilik TemelleriInterface'ler ile Çok BiçimlilikÇalışma Zamanı Tip Kontrolüis ve as OperatörleriCovariant Anahtar KelimesiÖzet - Ödeme İşlemcisi12Asenkron OOP
Futures ve async/awaitStream TemelleriStream Controller'larAsenkron KurucularSınıf Metotlarında Asenkron KullanımıÖzet - Data Fetcher15Tasarı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ıRepository Kalıbı