Repository Kalıbı
Coddy'nin Dart Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 100 / 110.
Repository deseni, uygulamanız ile veri kaynakları arasında bir soyutlama katmanı oluşturarak veri erişim mantığını iş mantığından ayırır. Sınıflarınızın veritabanları, API'ler veya dosyalarla doğrudan etkileşime girmesi yerine, tüm veri işlemlerini yöneten bir repository ile çalışırlar.
Desen, veri işlemleri için bir arayüz tanımlar ve somut uygulamalar gerçek depolama mekanizmasını yönetir. Bu, iş mantığınızı değiştirmeden veri kaynaklarını değiştirmeyi kolaylaştırır:
// Varlık (Entity)
class User {
final int id;
final String name;
User(this.id, this.name);
}
// Repository arayüzü
abstract class UserRepository {
User? getById(int id);
List<User> getAll();
void save(User user);
void delete(int id);
}
// Bellek içi implementasyon
class InMemoryUserRepository implements UserRepository {
final Map<int, User> _users = {};
@override
User? getById(int id) => _users[id];
@override
List<User> getAll() => _users.values.toList();
@override
void save(User user) => _users[user.id] = user;
@override
void delete(int id) => _users.remove(id);
}
void main() {
UserRepository repo = InMemoryUserRepository();
repo.save(User(1, 'Alice'));
repo.save(User(2, 'Bob'));
print(repo.getById(1)?.name); // Alice
print(repo.getAll().length); // 2
}İş mantığınız yalnızca UserRepository arayüzüne bağlıdır. Daha sonra aynı arayüzü uygulayan bir DatabaseUserRepository veya ApiUserRepository oluşturabilir ve depoyu kullanan hiçbir kodu değiştirmeden uygulamaları birbirleriyle değiştirebilirsiniz. Bu desen, veri kaynaklarının zamanla değişebileceği test edilebilir ve bakımı kolay uygulamalar için temeldir.
Görev
KolayRepository desenini kullanarak bir ürün envanter sistemi oluşturalım! Ürünlerin nasıl saklandığını nasıl kullanıldıklarından ayıran bir soyutlama katmanı oluşturacaksınız; bu sayede iş mantığını değiştirmeden depolama uygulamalarını değiştirmek kolaylaşacak.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
product_repository.dart: Bu dosya, varlık (entity) ve repository sınıflarınızı içerir.id(int),name(String) veprice(double) içinfinalalanlara sahip birProductsınıfı ile başlayın. Ardından, veri işlemleri için sözleşmeyi bildiren soyut birProductRepositorysınıfı tanımlayın: null dönebilen birProductdöndürengetById(int id), ürün listesi döndürengetAll(), bir ürünü kaydetmek içinsave(Product product)ve bir ürünü silmek içindelete(int id). Son olarak, depolama için birMap<int, Product>kullanarak bu arayüzü (interface) uygulayan birInMemoryProductRepositoryoluşturun.main.dart: Repository dosyanızı içe aktarın ve Repository desenini iş başında gösterin. BirInMemoryProductRepositoryoluşturun ancak bunuProductRepositorytipinde bir değişkende saklayın - bu, kodunuzun uygulamaya değil, arayüze nasıl bağımlı olduğunu gösterir. Üç ürün kaydedin:Laptop(id: 1, price: 999.99),Mouse(id: 2, price: 29.99) veKeyboard(id: 3, price: 79.99). Ardından id'si 2 olan ürünü getirin veFound: [name] - $[price]formatında yazdırın. id'si 1 olan ürünü silin. Son olarak, kalan ürünlerin sayısınıProducts in stock: [count]olarak yazdırın.
Bu desenin gücü, ana kodunuzun yalnızca ProductRepository arayüzünü bilmesidir. Daha sonra bir DatabaseProductRepository veya ApiProductRepository oluşturabilir ve iş mantığından hiçbirini değiştirmeden bunları birbirinin yerine kullanabilirsiniz!
Beklenen çıktı:
Found: Mouse - $29.99
Products in stock: 2Kopya kağıdı
Repository deseni, uygulamanız ile veri kaynakları arasında bir soyutlama katmanı oluşturarak veri erişim mantığını iş mantığından ayırır.
Veri işlemleri için bir arayüz tanımlayın:
// Varlık (Entity)
class User {
final int id;
final String name;
User(this.id, this.name);
}
// Repository arayüzü
abstract class UserRepository {
User? getById(int id);
List<User> getAll();
void save(User user);
void delete(int id);
}Gerçek depolama mekanizmasını yöneten somut uygulamalar oluşturun:
// Bellek içi (In-memory) uygulama
class InMemoryUserRepository implements UserRepository {
final Map<int, User> _users = {};
@override
User? getById(int id) => _users[id];
@override
List<User> getAll() => _users.values.toList();
@override
void save(User user) => _users[user.id] = user;
@override
void delete(int id) => _users.remove(id);
}Repository'yi arayüzü üzerinden kullanın:
void main() {
UserRepository repo = InMemoryUserRepository();
repo.save(User(1, 'Alice'));
repo.save(User(2, 'Bob'));
print(repo.getById(1)?.name); // Alice
print(repo.getAll().length); // 2
}İş mantığı yalnızca arayüze bağlıdır; bu da repository'yi kullanan kodu değiştirmeden uygulamaları (örneğin, DatabaseUserRepository, ApiUserRepository) değiştirmenize olanak tanır.
Kendin dene
import 'product_repository.dart';
void main() {
// Depoyu oluşturun - türün uygulama değil, arayüz (interface) olduğuna dikkat edin
// TODO: Bir InMemoryProductRepository oluşturun ve bunu bir ProductRepository değişkeninde saklayın
// TODO: Üç ürün kaydedin:
// - Laptop (id: 1, price: 999.99)
// - Mouse (id: 2, price: 29.99)
// - Keyboard (id: 3, price: 79.99)
// TODO: id değeri 2 olan ürünü getirin ve yazdırın: "Found: [name] - $[price]"
// TODO: id değeri 1 olan ürünü silin
// TODO: Kalan ürünlerin sayısını yazdırın: "Products in stock: [count]"
}
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ı