Mixin vs Arayüz
Coddy'nin Dart Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 55 / 110.
Mixin'lerin kalıtımla (inheritance) nasıl karşılaştırıldığını gördünüz. Şimdi mixin'leri arayüzlerle (interfaces) karşılaştıralım, çünkü her ikisi de birden fazla tiple çalışmanıza olanak tanır. Temel fark sağladıkları şeydir: arayüzler bir sözleşme (contract) tanımlarken, mixin'ler uygulama (implementation) sağlar.
Bir arayüzü (interface) uyguladığınızda, belirli metotları sağlamayı taahhüt edersiniz, ancak tüm kodu kendiniz yazarsınız. Bir mixin kullandığınızda ise, asıl kodu hazır olarak alırsınız.
// Arayüz yaklaşımı - her şeyi uygulamanız gerekir
abstract class Printable {
void printInfo();
}
class Report implements Printable {
@override
void printInfo() {
print('Printing report...'); // Bunu siz yazarsınız
}
}
// Mixin yaklaşımı - uygulama dahildir
mixin Printable {
void printInfo() {
print('Printing...'); // Sizin için zaten yazıldı
}
}
class Report with Printable {} // printInfo() işlevini otomatik olarak alırPeki, her birini ne zaman kullanmalısınız? Farklı sınıfların aynı metot imzalarına ancak farklı uygulamalara ihtiyaç duyduğu durumlarda bir interface kullanın. Sınıfların tam olarak aynı davranışı paylaşması gerektiğinde bir mixin kullanın.
| Özellik | Arayüz (Interface) | Mixin |
|---|---|---|
| Sağlar | Yalnızca sözleşme | Sözleşme + kod |
| Uygulama | Siz yazarsınız | Dahil edilmiş |
| Anahtar Kelime | implements | with |
| En iyi kullanım alanı | Farklı davranışlar, aynı API | Paylaşılan davranış |
Her iki yaklaşımı da birleştirebilirsiniz - bir sınıfın neler yapabileceğini tanımlamak için arayüzleri (interfaces) ve uygun yerlerde ortak uygulamalar sağlamak için mixin'leri kullanın. Dart'ta, her ikisini birleştirirken, her zaman with ifadesini implements ifadesinden önce koyun:
class MyClass with SomeMixin implements SomeInterface {
// with, implements'tan önce gelir
}Görev
KolayArayüzlerin (interfaces) mixin'lere karşı ne zaman kullanılacağını gösteren bir bildirim sistemi oluşturalım. Farklı uygulamalar gerektiren bildirimler için bir arayüz ve tüm bildirim türlerinde aynı olması gereken paylaşılan günlükleme (logging) davranışı için bir mixin oluşturacaksınız.
Kodunuzu üç dosyada düzenleyeceksiniz:
notifiable.dart: Bir arayüz görevi görenNotifiablesoyut sınıfını tanımlayın. İki soyut yöntem bildirmelidir:send(String message)ve birStringdöndürengetChannel(). Farklı bildirim türleri, bu yöntemleri kendi özel kanallarına göre farklı şekilde uygulayacaktır.logging.dart: Tüm bildirimlerin sahip olması gereken paylaşılan davranışı sağlayan birLoggingmixin'i oluşturun.[LOG] Sent via [channel]: [message]yazdıran birlogSent(String channel, String message)yöntemi ve[LOG] Timestamp recordedyazdıran birlogTimestamp()yöntemi ekleyin. Bu davranış tüm bildirim türleri için aynıdır, bu da onu bir mixin için mükemmel kılar.main.dart: Her iki dosyayı da içe aktarın ve arayüzü mixin ile birleştiren iki bildirim sınıfı oluşturun:Loggingmixin'ini kullanan veNotifiablearayüzünü uygulayan birEmailNotificationsınıfı.getChannel()yöntemi'Email'döndürmeli vesend()yöntemiSending email: [message]yazdırmalı, ardından kanal ve mesajla birliktelogSent()yöntemini çağırmalı ve son olaraklogTimestamp()yöntemini çağırmalıdır.Loggingmixin'ini kullanan veNotifiablearayüzünü uygulayan birSMSNotificationsınıfı.getChannel()yöntemi'SMS'döndürmeli vesend()yöntemiSending SMS: [message]yazdırmalı, ardından kanal ve mesajla birliktelogSent()yöntemini çağırmalı ve son olaraklogTimestamp()yöntemini çağırmalıdır.
EmailNotificationoluşturun vesend('Hello World')yöntemini çağırın, boş bir satır yazdırın, birSMSNotificationoluşturun vesend('Quick update')yöntemini çağırın.
Arayüzün her sınıfı kendi send() ve getChannel() uygulamalarını yazmaya nasıl zorladığına (farklı davranış), mixin'in ise her ikisi için de aynı şekilde çalışan günlükleme yöntemlerini nasıl sağladığına (paylaşılan davranış) dikkat edin.
Beklenen çıktı:
Sending email: Hello World
[LOG] Sent via Email: Hello World
[LOG] Timestamp recorded
Sending SMS: Quick update
[LOG] Sent via SMS: Quick update
[LOG] Timestamp recordedKopya kağıdı
Arayüzler (Interfaces) bir sözleşme (metot imzaları) tanımlarken, mixin'ler uygulama (gerçek kod) sağlar.
Bir arayüzü uyguladığınızda (implement), tüm kodu kendiniz yazmalısınız:
abstract class Printable {
void printInfo();
}
class Report implements Printable {
@override
void printInfo() {
print('Printing report...'); // Bunu siz yazarsınız
}
}Bir mixin kullandığınızda, uygulamayı hazır olarak alırsınız:
mixin Printable {
void printInfo() {
print('Printing...'); // Sizin için zaten yazılmıştır
}
}
class Report with Printable {} // printInfo() fonksiyonunu otomatik olarak alırHangisi ne zaman kullanılmalı:
- Farklı sınıflar aynı metot imzalarına ancak farklı uygulamalara ihtiyaç duyduğunda bir arayüz kullanın
- Sınıflar tamamen aynı davranışı paylaşması gerektiğinde bir mixin kullanın
| Özellik | Arayüz | Mixin |
|---|---|---|
| Sağlar | Sadece sözleşme | Sözleşme + kod |
| Uygulama | Siz yazarsınız | Dahildir |
| Anahtar Kelime | implements | with |
| En iyi kullanım alanı | Farklı davranışlar, aynı API | Paylaşılan davranış |
Her iki yaklaşımı da birleştirebilirsiniz. Birleştirirken, her zaman with ifadesini implements ifadesinden önce koyun:
class MyClass with SomeMixin implements SomeInterface {
// with, implements'ten önce gelir
}Kendin dene
import 'notifiable.dart';
import 'logging.dart';
// TODO: Şu özelliklere sahip EmailNotification sınıfını oluşturun:
// - Logging mixin'ini kullanır (with)
// - Notifiable arayüzünü uygular (implements)
// - getChannel() 'Email' değerini döndürür
// - send() 'Sending email: [message]' yazdırır, ardından logSent() ve logTimestamp() fonksiyonlarını çağırır
// TODO: Şu özelliklere sahip SMSNotification sınıfını oluşturun:
// - Logging mixin'ini kullanır (with)
// - Notifiable arayüzünü uygular (implements)
// - getChannel() 'SMS' değerini döndürür
// - send() 'Sending SMS: [message]' yazdırır, ardından logSent() ve logTimestamp() fonksiyonlarını çağırır
void main() {
// TODO: Bir EmailNotification oluşturun ve send('Hello World') fonksiyonunu çağırın
// TODO: Boş bir satır yazdırın
// TODO: Bir SMSNotification oluşturun ve send('Quick update') fonksiyonunu çağı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 Depolama2Dart'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ı