Repository Kalıbı
Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 81 / 91.
Repository Pattern, uygulamanızın iş mantığı ile veri depolama katmanı arasında aracılık eden bir tasarım desenidir. Verilerin gerçekte nasıl saklandığı veya getirildiğiyle ilgili ayrıntıları gizleyerek, alan (domain) nesnelerine erişmek için koleksiyon benzeri bir arayüz sağlar.
Bir depoyu (repository), nesneleri nasıl kalıcı hale getireceğini ve geri getireceğini bilen özel bir koleksiyon olarak düşünün. Uygulama kodunuz, verilerin bir veritabanında mı, dosyada mı yoksa bir API'de mi olduğunu bilmeden, depodan ID'ye göre bir kullanıcı ister veya yeni bir ürün kaydeder. Bu ayrım, kodunuzu daha test edilebilir ve esnek hale getirir.
<?php
interface UserRepositoryInterface {
public function find(int $id): ?User;
public function findAll(): array;
public function save(User $user): void;
public function delete(int $id): void;
}
class User {
public function __construct(
public int $id,
public string $name,
public string $email
) {}
}
Repository (depo) uygulaması, gerçek depolama mekanizmasını yönetir:
<?php
class InMemoryUserRepository implements UserRepositoryInterface {
private array $users = [];
public function find(int $id): ?User {
return $this->users[$id] ?? null;
}
public function findAll(): array {
return array_values($this->users);
}
public function save(User $user): void {
$this->users[$user->id] = $user;
}
public function delete(int $id): void {
unset($this->users[$id]);
}
}
$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$repo->save(new User(2, "Bob", "bob@example.com"));
echo $repo->find(1)->name . "\n";
echo count($repo->findAll());
Çıktı:
Alice
2Bu desenin güzelliği, iş mantığınızı değiştirmeden uygulamaları değiştirebilmenizdir. Bellek içi depolamadan bir veritabanına geçmeniz mi gerekiyor? Aynı arayüzü uygulayan yeni bir repository sınıfı oluşturun. Uygulama kodunuz dokunulmadan kalır çünkü somut uygulamaya değil, arayüze bağlıdır.
Görev
KolayRepository Desenini kullanarak bir ürün envanter sistemi oluşturalım. Alan (domain) nesneleriniz ile bunların nasıl saklandığı arasında temiz bir ayrım oluşturacaksınız; bu da uygulama kodunuzun saklama detaylarını bilmeden ürünlerle çalışmasına olanak tanıyacaktır.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
Product.php— Envanterinizdeki öğeleri temsil eden birProductsınıfı oluşturun. Her ürünün birid(int),name(string) veprice(float) değeri vardır. Kolay erişim için genel (public) özelliklerle birlikte yapıcı (constructor) tanıtımını kullanın.ProductRepositoryInterface.php— Herhangi bir ürün saklama uygulaması için sözleşmeyi belirleyen birProductRepositoryInterfacetanımlayın. Arayüzünüz şu yöntemleri bildirmelidir:find(int $id): ?Product— Bir ürünü ID'ye göre getirir veya bulunamazsa null dönerfindAll(): array— Tüm ürünleri bir dizi olarak getirirsave(Product $product): void— Bir ürünü saklar veya güncellerdelete(int $id): void— Bir ürünü ID'ye göre siler
InMemoryProductRepository.php— Hem Product sınıfını hem de arayüzü dahil edin. Ürünleri saklamak için özel (private) bir dizi kullanarak arayüzü uygulayan birInMemoryProductRepositorysınıfı oluşturun. Ürünler, verimli arama için ID'lerine göre dizinlenmelidir.findAll()yöntemi yalnızca ürün nesnelerini döndürmelidir (dizi anahtarlarını sıfırlamak içinarray_values()kullanın).main.php— Depo (repository) dosyasını dahil edin. Bir girdi alacaksınız: eklenecek ürünlerin dizisini içeren bir JSON dizesi ve ardından aranacak bir ID.JSON formatı şu şekilde olacaktır:
[{"id": 1, "name": "Laptop", "price": 999.99}, {"id": 2, "name": "Mouse", "price": 29.99}]Bir
InMemoryProductRepositoryoluşturun, JSON girdisindeki tüm ürünleri kaydedin, ardından belirli bir ürünü bulmak için ikinci girdiyi (ID) kullanın. Sonuçları şu formatta yazdırın:Total products: [count] Found: [name] - $[price]Fiyatı iki ondalık basamak olacak şekilde biçimlendirin. Ürün bulunamazsa, bunun yerine
Found: Not foundyazdırın.
Repository Deseni, saklama uygulamalarını değiştirmeniz gerektiğinde parlar. Ana kodunuz yalnızca arayüzüne bağlıdır; bellek içi saklamadan bir veritabanına geçmek, herhangi bir uygulama mantığını değiştirmeden yeni bir depo sınıfı oluşturmak anlamına gelir.
Kopya kağıdı
Repository Pattern (Depo Deseni), iş mantığı ile veri depolama arasında aracılık yaparak, depolama uygulama detaylarını gizlerken alan nesnelerine erişmek için koleksiyon benzeri bir arayüz sağlar.
Veri erişimi için sözleşmeyi belirleyen bir repository arayüzü tanımlayın:
<?php
interface UserRepositoryInterface {
public function find(int $id): ?User;
public function findAll(): array;
public function save(User $user): void;
public function delete(int $id): void;
}Yapıcı (constructor) tanıtımını kullanarak bir alan (domain) sınıfı oluşturun:
<?php
class User {
public function __construct(
public int $id,
public string $name,
public string $email
) {}
}Repository arayüzünü somut bir depolama mekanizması ile uygulayın:
<?php
class InMemoryUserRepository implements UserRepositoryInterface {
private array $users = [];
public function find(int $id): ?User {
return $this->users[$id] ?? null;
}
public function findAll(): array {
return array_values($this->users);
}
public function save(User $user): void {
$this->users[$user->id] = $user;
}
public function delete(int $id): void {
unset($this->users[$id]);
}
}Repository'yi arayüzü üzerinden kullanın:
$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$user = $repo->find(1);
$allUsers = $repo->findAll();Bu desen, iş mantığını değiştirmeden uygulamaların yer değiştirilmesine olanak tanır — kodunuz somut uygulamaya değil, arayüze bağlıdır.
Kendin dene
<?php
require_once 'InMemoryProductRepository.php';
// Girdiyi oku
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));
// JSON girdisini bir diziye dönüştür
$productsData = (array)json_decode($jsonInput, true);
// TODO: Bir InMemoryProductRepository örneği oluşturun
// TODO: $productsData üzerinde döngü kurun ve her bir ürünü kaydedin
// Her öğe 'id', 'name' ve 'price' anahtarlarına sahiptir
// TODO: Tüm ürünleri alın ve toplam sayıyı yazdırın
// Format: "Total products: [count]"
// TODO: $searchId ile eşleşen ürünü bulun
// Eğer bulunursa, şunu yazdırın: "Found: [name] - $[price]" (fiyat 2 ondalık basamaklı formatta olmalıdır)
// Eğer bulunamazsa, şunu yazdırın: "Found: Not found"
?>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 DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarı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ı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarı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ı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi