Menu
Coddy logo textTech

Soyut Sınıflar ve Arayüzler

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

Artık hem soyut sınıfları hem de arayüzleri anladığınıza göre, yaygın bir soru ortaya çıkıyor: birini diğerine ne zaman tercih etmelisiniz? Seçim, neyi modellemeye çalıştığınıza bağlıdır.

Sınıflar, paylaşılan bir durum veya davranışa sahip ortak bir temeli paylaştığında bir soyut sınıf (abstract class) kullanın. Soyut sınıflar; örnek değişkenlerine, yapılandırıcılara ve soyut ile somut metotların bir karışımına sahip olabilir:

public abstract class Animal {
    protected String name;  // paylaşılan durum
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void sleep() {  // paylaşılan davranış
        System.out.println(name + " is sleeping");
    }
    
    public abstract void makeSound();  // uygulanmalıdır
}

İlişkisiz sınıfların paylaşabileceği bir yetenek tanımlamak istediğinizde bir interface kullanın. Interface'ler bir nesnenin ne olduğuna değil, ne yapabildiğine odaklanır:

public interface Flyable {
    void fly();
}

// İlişkisiz sınıflar bu yeteneği paylaşabilir
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }

İşte hızlı bir karşılaştırma:

ÖzellikAbstract ClassInterface
Örnek değişkenleriEvetSadece sabitler
Yapıcılar (Constructors)EvetHayır
Çoklu kalıtımHayır (tekli extends)Evet (çoklu implements)
Erişim belirleyicileriHerhangi biriSadece public (soyut metotlar için)

Pratik bir kural: Kendinizi yalnızca soyut metotları olan ve durumu (state) bulunmayan bir abstract class oluştururken bulursanız, bir interface muhtemelen daha iyi bir seçimdir.

challenge icon

Görev

Kolay

Soyut sınıfların ne zaman kullanılacağını ve arayüzlerin (interfaces) ne zaman kullanılacağını gösteren bir araç sistemi oluşturalım. Ortak durum ve davranışları paylaşan araçları bir soyut sınıf aracılığıyla modelleyecek, isteğe bağlı yetenekleri ise arayüzler aracılığıyla ekleyeceksiniz.

Kodunuzu beş dosya halinde düzenleyeceksiniz:

  • Vehicle.java: Tüm araçlar için temel teşkil eden soyut bir sınıf oluşturun. Her aracın bir brand alanı (String) ve bir year alanı (int) vardır. Her iki alanı da başlatan bir yapıcı (constructor), her biri için getter metotları ve String döndüren soyut bir startEngine() metodu ekleyin. Ayrıca şu formatta değer döndüren somut bir getInfo() metodu ekleyin: [brand] ([year]). Bu, soyut bir sınıf için mükemmel bir kullanım örneğidir; araçlar durumu (brand, year) ve bazı davranışları (getInfo) paylaşır, ancak her biri motorunu farklı şekilde çalıştırır.
  • Convertible.java: Tavanı açılıp kapanabilen araçlar için bir arayüz tanımlayın. Bu yetenek bir aracın ne olduğuyla ilgili değil, belirli araçların yapabildiği bir şeydir. Her ikisi de String döndüren iki metot bildirin: openRoof() ve closeRoof().
  • Car.java: Vehicle sınıfını genişleten ve Convertible arayüzünü uygulayan bir sınıf oluşturun. Bir Car'ın ek bir numDoors alanı (int) vardır. Devralınan alanları başlatmak için super kullanın. startEngine() metodunu [brand] car engine started döndürecek şekilde uygulayın. openRoof() metodunu [brand] roof opening ve closeRoof() metodunu [brand] roof closing döndürecek şekilde uygulayın.
  • Motorcycle.java: Vehicle sınıfını genişleten ancak Convertible arayüzünü uygulamayan bir sınıf oluşturun; motosikletlerin tavanı yoktur! Bir Motorcycle'ın hasSidecar alanı (boolean) vardır. startEngine() metodunu [brand] motorcycle engine roaring döndürecek şekilde uygulayın.
  • Main.java: Soyut sınıflar ve arayüzler arasındaki farkı göstermek için her şeyi bir araya getirin. Dört girdi alacaksınız: bir araba markası, bir araba yılı, bir motosiklet markası ve bir motosiklet yılı.

    Bir Car (4 kapılı) ve bir Motorcycle (sepeti olmayan) oluşturun. İlk olarak, her iki araç için getInfo() çıktısını yazdırarak paylaşılan soyut sınıf davranışını gösterin; her ikisi de bunu Vehicle sınıfından devralır. Ardından her biri için startEngine() sonucunu yazdırın; her araç tipinin bunu nasıl farklı şekilde uyguladığına dikkat edin.

    Son olarak, arayüz yeteneğini gösterin: Sadece Car sınıfı Convertible arayüzünü uyguladığı için, sadece araba üzerinde openRoof() ve ardından closeRoof() metotlarını çağırın ve yazdırın.

Dört girdi alacaksınız: araba markası (String), araba yılı (int), motosiklet markası (String) ve motosiklet yılı (int).

Çıktınız toplam altı satır olmalıdır. Her iki aracın da soyut sınıfın durumunu ve getInfo() metodunu nasıl paylaştığına, ancak yalnızca Car'ın üstü açılabilir (convertible) yeteneğine sahip olduğuna dikkat edin; bu, her bir yaklaşımın ne zaman kullanılacağını gösterir!

Kopya kağıdı

Sınıflar ortak bir durum veya davranışa sahip ortak bir temeli paylaştığında bir soyut sınıf (abstract class) kullanın. Soyut sınıflar örnek değişkenlerine, yapıcılara (constructors) ve soyut ile somut metotların bir karışımına sahip olabilir:

public abstract class Animal {
    protected String name;  // paylaşılan durum
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void sleep() {  // paylaşılan davranış
        System.out.println(name + " is sleeping");
    }
    
    public abstract void makeSound();  // uygulanmalıdır
}

İlişkisiz sınıfların paylaşabileceği bir yetenek tanımlamak istediğinizde bir arayüz (interface) kullanın. Arayüzler bir nesnenin ne olduğuna değil, ne yapabildiğine odaklanır:

public interface Flyable {
    void fly();
}

// İlişkisiz sınıflar bu yeteneği paylaşabilir
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }
ÖzellikSoyut Sınıf (Abstract Class)Arayüz (Interface)
Örnek değişkenleriEvetSadece sabitler
Yapıcılar (Constructors)EvetHayır
Çoklu kalıtımHayır (tekli extends)Evet (çoklu implements)
Erişim belirleyicilerHerhangi biriSadece public (soyut metotlar için)

Kılavuz: Eğer sadece soyut metotları olan ve hiçbir durumu (state) bulunmayan bir soyut sınıf oluşturuyorsanız, muhtemelen bir arayüz daha iyi bir seçimdir.

Kendin dene

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Girdileri oku
        String carBrand = scanner.nextLine();
        int carYear = scanner.nextInt();
        scanner.nextLine(); // satır sonu karakterini tüket
        String motorcycleBrand = scanner.nextLine();
        int motorcycleYear = scanner.nextInt();
        
        // TODO: 4 kapılı bir Araba (Car) oluşturun
        
        // TODO: Sepeti olmayan (false) bir Motosiklet (Motorcycle) oluşturun
        
        // TODO: Her iki araç için getInfo() metodunu yazdırın (paylaşılan soyut sınıf davranışını gösterir)
        
        // TODO: Her iki araç için startEngine() metodunu yazdırın (farklı uygulamaları gösterir)
        
        // TODO: Sadece araba için openRoof() ve closeRoof() metodlarını yazdırın (arayüz yeteneğini gösterir)
    }
}
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