Menu
Coddy logo textTech

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ır

Peki, 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.

ÖzellikArayüz (Interface)Mixin
SağlarYalnızca sözleşmeSözleşme + kod
UygulamaSiz yazarsınızDahil edilmiş
Anahtar Kelimeimplementswith
En iyi kullanım alanıFarklı davranışlar, aynı APIPaylaşı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
}
challenge icon

Görev

Kolay

Arayü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ören Notifiable soyut sınıfını tanımlayın. İki soyut yöntem bildirmelidir: send(String message) ve bir String döndüren getChannel(). 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 bir Logging mixin'i oluşturun. [LOG] Sent via [channel]: [message] yazdıran bir logSent(String channel, String message) yöntemi ve [LOG] Timestamp recorded yazdıran bir logTimestamp() 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:
    • Logging mixin'ini kullanan ve Notifiable arayüzünü uygulayan bir EmailNotification sınıfı. getChannel() yöntemi 'Email' döndürmeli ve send() yöntemi Sending email: [message] yazdırmalı, ardından kanal ve mesajla birlikte logSent() yöntemini çağırmalı ve son olarak logTimestamp() yöntemini çağırmalıdır.
    • Logging mixin'ini kullanan ve Notifiable arayüzünü uygulayan bir SMSNotification sınıfı. getChannel() yöntemi 'SMS' döndürmeli ve send() yöntemi Sending SMS: [message] yazdırmalı, ardından kanal ve mesajla birlikte logSent() yöntemini çağırmalı ve son olarak logTimestamp() yöntemini çağırmalıdır.
    Ardından bir EmailNotification oluşturun ve send('Hello World') yöntemini çağırın, boş bir satır yazdırın, bir SMSNotification oluşturun ve send('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 recorded

Kopya 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ır

Hangisi 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
ÖzellikArayüzMixin
SağlarSadece sözleşmeSözleşme + kod
UygulamaSiz yazarsınızDahildir
Anahtar Kelimeimplementswith
En iyi kullanım alanıFarklı davranışlar, aynı APIPaylaşı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
}
quiz iconKendini test et

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