Menu
Coddy logo textTech

Arayüz vs Soyut Sınıf

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

Artık hem arayüzleri hem de soyut sınıfları öğrendiğinize göre, her birini ne zaman kullanacağınızı netleştirelim. Birbirlerine benzer görünseler de, farklı amaçlara hizmet ederler ve belirgin yetenekleri vardır.

Özellik Interface (Arayüz) Abstract Class (Soyut Sınıf)
Metotlar Sadece metot imzaları Hem soyut hem de somut metotlar
Özellikler (Properties) Sadece sabitler Özelliklere sahip olabilir
Çoklu kalıtım Bir sınıf birden fazlasını uygulayabilir (implement) Bir sınıf sadece birini genişletebilir (extend)
Yapıcı Metot (Constructor) Bir __construct imzası bildirebilir (gövdesiz) Gövdesi olan bir yapıcı metot tanımlayabilir

Birbiriyle ilişkisi olmayan sınıfların karşılayabileceği bir sözleşme tanımlamak istediğinizde bir interface kullanın. Örneğin, hem bir Printer hem de bir Logger, ortak bir ataya sahip olmasalar bile bir Writable interface'ini uygulayabilir.

Ortak kod paylaşan ilişkili sınıflarınız olduğunda bir soyut sınıf kullanın. Eğer Dog ve Cat sınıflarınızın her ikisi de aynı eat() metot uygulamasına ihtiyaç duyuyorsa, soyut bir Animal sınıfı bu kodu bir kez yazmanıza olanak tanır.

Her iki yaklaşımı da birleştirebilirsiniz. Bir sınıf, birden fazla arayüzü uygularken bir soyut sınıfı genişletebilir:

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

Önemli Nokta: İlişkisiz sınıflar arasında yetenekleri tanımlamak için arayüzleri (interfaces) seçin. İlişkili sınıflar arasında kod paylaşmanız gerektiğinde soyut sınıfları (abstract classes) seçin.

challenge icon

Görev

Kolay

Soyut bir sınıfın ne zaman kullanılacağı ile bir arayüzün (interface) ne zaman kullanılacağını ve her iki yaklaşımın nasıl etkili bir şekilde birleştirileceğini gösteren bir araç sistemi oluşturalım.

Araçların kalıtım yoluyla ortak özellikleri paylaştığı, ancak arayüzler aracılığıyla ek yetenekler kazanabildiği bir sistem oluşturacaksınız. Bu, gerçek dünyadaki tasarım kararlarını yansıtır: bir araba bir araçtır ("is a" - kalıtım), ancak aynı zamanda yakıt doldurulabilir olma ("has the capability" - arayüz) yeteneğine de sahiptir.

Kodunuzu dört dosya halinde düzenleyin:

  • Refuelable.php — Tek bir metot imzasına sahip bir Refuelable arayüzü tanımlayın: refuel($amount). Bu yetenek, kalıtım hiyerarşisinden bağımsız olarak yakıt ikmali gerektiren herhangi bir sınıfa uygulanabilir.
  • Vehicle.php — Tüm araçlar için paylaşılan işlevsellik sağlayan soyut bir Vehicle sınıfı tanımlayın. Korumalı (protected) bir $brand özelliğine ve korumalı bir $fuelLevel özelliğine (0'dan başlayan) sahip olmalıdır. Kurucu metot (constructor) marka adını kabul eder. Markayı döndüren somut bir getBrand() metodu, mevcut yakıt seviyesini döndüren somut bir getFuelLevel() metodu ve alt sınıfların uygulaması gereken soyut bir drive() metodu ekleyin.
  • Car.phpVehicle sınıfını genişleten ve Refuelable arayüzünü uygulayan bir Car sınıfı oluşturun. Gerekli her iki dosyayı da en üste dahil edin. Kurucu metot markayı kabul eder ve bunu üst sınıfın kurucusuna iletir. drive() metodunu "[brand] car is driving" döndürecek şekilde uygulayın. refuel($amount) metodunu, miktarı yakıt seviyesine ekleyecek ve "[brand] refueled to [fuelLevel] liters" döndürecek şekilde uygulayın.
  • main.php — Car dosyasını dahil edin. İki girdi alacaksınız: bir marka adı ve bir yakıt miktarı (tam sayıya dönüştürün). Marka ile bir Car nesnesi oluşturun. İlk satıra drive() sonucunu yazdırın, ardından ikinci satıra yakıt miktarı ile refuel() sonucunu yazdırın.

Bu zorluk temel ayrımı göstermektedir: soyut Vehicle sınıfı kodu paylaşır ve bir "is-a" (bir ...-dır) ilişkisi kurar; Refuelable arayüzü ise araç olmalarını gerektirmeden diğer ilgisiz sınıflara (jeneratör veya tekne gibi) uygulanabilecek bir yetenek ekler.

Kendin dene

<?php
require_once 'Car.php';

// Girdiyi oku
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO: Marka ile bir Car oluştur

// TODO: İlk satıra drive() sonucunu yazdır

// TODO: İkinci satıra yakıt miktarı ile refuel() sonucunu yazdır
?>
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