TEKNİK YAZI / Developer Tools ve Açık Kaynak

Flutter Extension Methods: Var Olan Tiplere Davranış Eklemek

Dart extension methods ile var olan tiplere statik olarak çözümlenen davranış eklemeyi, kapsam ve isim çakışması sınırlarıyla öğrenin.

Dart extension methods, kaynak kodunu veya kalıtım zincirini değiştirmeden var olan bir tip üzerinde yeni bir çağrı yüzeyi tanımlar. Çözümleme statiktir; extension’ın kapsamda olması, alıcı tipinin eşleşmesi ve olası isim çakışmalarının açıkça yönetilmesi gerekir.

Extension Methods Nedir?

Extension method’lar, var olan class’lara source code’unu değiştirmeden yeni method’lar eklemenizi sağlıyor. Yani String, int, List gibi built-in class’lara bile kendi method’larınızı ekleyebiliyorsunuz. Inheritance yapmadan, wrapper class yazmadan!

Örneğin String üzerinde projeye özgü bir biçimlendirme davranışı tanımlamak için wrapper veya alt sınıf kurmak yerine extension kullanılabilir. Bu yöntem gerçek sınıfa üye eklemez; yalnızca derleyicinin kapsamda çözümlediği statik bir çağrı sağlar.

Neden Extension Methods?

Utility function’lar yerine: StringUtils.capitalize(text) yerine text.capitalize() yazmak çok daha doğal ve okunabilir.

Domain-specific logic: Projenize özel method’lar ekleyebilirsiniz. user.isAdmin() gibi.

Chaining: Method chain’ler oluşturabilirsiniz. text.trim().capitalize().addPrefix("Hello")

Code organization: İlgili logic’i bir arada tutabilirsiniz.

Basit Örnekler

// String extension
extension StringExtras on String {
  // Capitalize first letter
  String get capitalized =>
    isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';

  // Check if email
  bool get isEmail => contains('@') && contains('.');
}

// Usage
final name = "john".capitalized; // "John"
final valid = "test@mail.com".isEmail; // true
// List extension with generics
extension ListExtras<T> on List<T> {
  // Get random element
  T get random => this[DateTime.now().millisecond % length];

  // Split into chunks
  List<List<T>> chunk(int size) {
    final chunks = <List<T>>[];
    for (var i = 0; i < length; i += size) {
      chunks.add(sublist(i, i + size > length ? length : i + size));
    }
    return chunks;
  }
}

// Usage
final items = [1, 2, 3, 4, 5];
final randomItem = items.random; // Random element
final chunks = items.chunk(2); // [[1,2], [3,4], [5]]

Flutter’da Extension Kullanımı

Flutter’da extension’lar muhteşem! Widget’lara padding eklemek, navigation’ı kolaylaştırmak, context helper’ları…

BuildContext extension’ları: Theme’e, MediaQuery’e kolay erişim için.

Widget extension’ları: Padding, margin wrapper’ları için.

DateTime extension’ları: Formatting, comparison için.

Nullable Types ile Extension

Dart’ın null safety özelliği ile extension’lar daha da güçlü:

extension NullableStringExtras on String? {
  bool get isNullOrEmpty => this == null || this!.isEmpty;

  String orDefault(String defaultValue) => this ?? defaultValue;
}

// Usage
String? name = null;
if (name.isNullOrEmpty) {
  print("Name is empty");
}
final displayName = name.orDefault("Guest"); // "Guest"

Extension vs Helper Class

Extension kullanın:

Helper class kullanın:

Best Practices

  1. İsimlendirme: Extension’lara açıklayıcı isimler verin. StringExtras, DateTimeHelpers gibi.

  2. Scope: Extension’ları kullanacağınız yerde import edin. Global namespace’i kirletmeyin.

  3. Conflict resolution: Aynı method ismi varsa, extension’ı hide edebilir veya prefix kullanabilirsiniz.

  4. Documentation: Extension method’larınızı document edin. IDE’de görünmesi için.

Performans

Extension method’lar compile time’da resolve ediliyor. Runtime overhead yok! Normal method call ile aynı performans.

Sonuç

Extension methods, küçük ve tip odaklı yardımcı davranışları çağrı noktasına yaklaştırır. Gizli bağımlılık üreten BuildContext kısayolları veya çok genel isimler ise kodun kökenini belirsizleştirebilir. Yalnızca tipin doğal sözlüğüne uyan, kapsamı açık ve çakışma riski düşük davranışları extension olarak tanımlayın.