Menu
Coddy logo textTech

Arayüzler ile Çok Biçimlilik

Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 34 / 91.

Önceki derste, alt sınıfların üst sınıf metotlarını geçersiz kıldığı (override ettiği) kalıtım yoluyla polimorfizmi gördünüz. Arayüzler, özellikle ortak davranışları paylaşan ilişkisiz sınıflarla çalışırken polimorfizm elde etmek için başka bir güçlü yol sunar.

Arayüzler ile polimorfizm sözleşmenin kendisinden gelir. Bir arayüzü uygulayan herhangi bir sınıf, kalıtım hiyerarşisinden bağımsız olarak belirli metotlara sahip olduğunu garanti eder:

<?php
interface Notifiable {
    public function send(string $message);
}

class EmailNotifier implements Notifiable {
    public function send(string $message) {
        return "Email: " . $message;
    }
}

class SMSNotifier implements Notifiable {
    public function send(string $message) {
        return "SMS: " . $message;
    }
}

class PushNotifier implements Notifiable {
    public function send(string $message) {
        return "Push: " . $message;
    }
}

function notify(Notifiable $notifier, string $message) {
    return $notifier->send($message);
}

echo notify(new EmailNotifier(), "Hello") . "\n";
echo notify(new SMSNotifier(), "Hello") . "\n";
echo notify(new PushNotifier(), "Hello");

Çıktı:

Email: Hello
SMS: Hello
Push: Hello

notify() fonksiyonu herhangi bir Notifiable nesnesi ile çalışır. Bu sınıflar bir üst sınıfı paylaşmazlar; aynı arayüzü uygulamaları dışında birbirleriyle tamamen alakasızdırlar. Kalıtım tabanlı polimorfizme karşı temel avantajı şudur: Alakasız sınıfları soylarına göre değil, yeteneklerine göre gruplandırabilirsiniz.

Önemli Nokta: Arayüz tabanlı polimorfizm, ilişkisiz sınıfların paylaşılan davranışlara dayalı olarak birbirinin yerine kullanılabilmesini sağlayarak kodunuzu daha esnek hale getirir ve belirli uygulamalardan ayrıştırır.

challenge icon

Görev

Kolay

Arayüz tabanlı polimorfizmi (çok biçimlilik) gösteren bir depolama sistemi inşa edelim. Aynı depolama arayüzünü uygulamaları dışında birbirleriyle hiçbir ortak noktası olmayan farklı depolama arka uçları —bir dosya sistemi ve bir veritabanı— oluşturacaksınız. Tek bir fonksiyon, herhangi bir depolama türüyle çalışarak arayüzlerin tamamen alakasız sınıflar arasında polimorfizmi nasıl sağladığını sergileyecek.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • Storable.php — İki metot imzasına sahip bir Storable arayüzü tanımlayın: save($key, $data) ve retrieve($key). Bu sözleşme, dahili olarak nasıl uygulandığına bakılmaksızın herhangi bir depolama sisteminin verileri depolayabilmesini ve geri alabilmesini sağlar.
  • FileStorage.phpStorable arayüzünü uygulayan bir FileStorage sınıfı oluşturun. Arayüz dosyasını dahil edin. Sınıf, yapıcı (constructor) aracılığıyla ayarlanan özel bir $directory özelliğine sahip olmalıdır. save($key, $data) metodunu "Saving '$data' to file $this->directory/$key.txt" döndürecek şekilde uygulayın. retrieve($key) metodunu "Reading from file $this->directory/$key.txt" döndürecek şekilde uygulayın.
  • DatabaseStorage.php — Yine Storable arayüzünü uygulayan bir DatabaseStorage sınıfı oluşturun. Arayüz dosyasını dahil edin. Sınıf, yapıcı aracılığıyla ayarlanan özel bir $tableName özelliğine sahip olmalıdır. save($key, $data) metodunu "Inserting '$data' into table $this->tableName with key $key" döndürecek şekilde uygulayın. retrieve($key) metodunu "Selecting from table $this->tableName where key = $key" döndürecek şekilde uygulayın.
  • main.php — Her iki depolama dosyasını da dahil edin. Bir Storable parametresi, bir anahtar ve veri kabul eden storeData adında bir fonksiyon oluşturun. Fonksiyon, anahtar ve veri ile save() metodunu çağırmanın sonucunu döndürmelidir. Bir Storable parametresi ve bir anahtar kabul eden, retrieve() metodunu çağırmanın sonucunu döndüren fetchData adında başka bir fonksiyon oluşturun.

Dört girdi alacaksınız: bir dizin yolu, bir tablo adı, bir anahtar ve depolanacak bazı veriler. Dizin ile bir FileStorage ve tablo adı ile bir DatabaseStorage oluşturun. Verileri önce dosya depolamasını, ardından veritabanı depolamasını kullanarak kaydetmek için storeData() fonksiyonunuzu kullanın. Her sonucu kendi satırında yazdırın. Ardından dosya depolamasından veri çekmek için fetchData() fonksiyonunu kullanın ve bu sonucu yazdırın.

storeData() ve fetchData() fonksiyonlarının her iki depolama türüyle de nasıl aynı şekilde çalıştığına dikkat edin — onlar sadece nesnenin Storable arayüzünü uygulayıp uygulamadığıyla ilgilenirler. Dosya sistemi ve veritabanı tamamen farklı dahili uygulamalara sahiptir, ancak arayüz sözleşmesi aracılığıyla birbirlerinin yerine kullanılabilirler.

Kopya kağıdı

Arayüzler (Interfaces), ilgisiz sınıfların kalıtım hiyerarşisinden ziyade paylaşılan davranışlara dayalı olarak birbirinin yerine kullanılmasına izin vererek polimorfizmi (çok biçimliliği) sağlar.

Bir arayüzü uygulayan herhangi bir sınıf, belirli metotlara sahip olduğunu garanti ederek polimorfik davranışı mümkün kılan bir sözleşme oluşturur:

<?php
interface Notifiable {
    public function send(string $message);
}

class EmailNotifier implements Notifiable {
    public function send(string $message) {
        return "Email: " . $message;
    }
}

class SMSNotifier implements Notifiable {
    public function send(string $message) {
        return "SMS: " . $message;
    }
}

function notify(Notifiable $notifier, string $message) {
    return $notifier->send($message);
}

echo notify(new EmailNotifier(), "Hello");
echo notify(new SMSNotifier(), "Hello");

notify() fonksiyonu, sınıf hiyerarşisinden bağımsız olarak Notifiable arayüzünü uygulayan herhangi bir nesneyi kabul eder. Bu, kodu daha esnek hale getirir ve belirli uygulamalardan bağımsızlaştırır.

Temel avantaj: Arayüz tabanlı polimorfizm, ilgisiz sınıfları soylarına göre değil, yeteneklerine göre gruplandırarak tamamen farklı uygulamaların ortak bir sözleşme aracılığıyla birbirinin yerine kullanılmasına olanak tanır.

Kendin dene

<?php
require_once 'FileStorage.php';
require_once 'DatabaseStorage.php';

// Girdileri oku
$directory = trim(fgets(STDIN));
$tableName = trim(fgets(STDIN));
$key = trim(fgets(STDIN));
$data = trim(fgets(STDIN));

// TODO: Bir Storable, anahtar (key) ve veri (data) kabul eden bir storeData fonksiyonu oluşturun
// Bu fonksiyon, anahtar ve veri ile save() metodunu çağırmanın sonucunu döndürmelidir

// TODO: Bir Storable ve anahtar (key) kabul eden bir fetchData fonksiyonu oluşturun
// Bu fonksiyon, anahtar ile retrieve() metodunu çağırmanın sonucunu döndürmelidir

// TODO: Dizin (directory) ile bir FileStorage örneği oluşturun

// TODO: Tablo adı (table name) ile bir DatabaseStorage örneği oluşturun

// TODO: Dosya depolama ile veriyi kaydetmek için storeData() kullanın, ardından sonucu yazdırın

// TODO: Veritabanı depolama ile veriyi kaydetmek için storeData() kullanın, ardından sonucu yazdırın

// TODO: Dosya depolamadan veri getirmek için fetchData() kullanın, ardından sonucu yazdı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